Skip to content
This repository has been archived by the owner on Dec 4, 2024. It is now read-only.

test: Add Codec trait unit tests #413

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions stacks-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ serde = { workspace = true, features = ["derive"] }
sha2.workspace = true
strum = { workspace = true, features = ["derive"] }
thiserror.workspace = true
anyhow.workspace = true
CAGS295 marked this conversation as resolved.
Show resolved Hide resolved

[dev-dependencies]
hex.workspace = true
Expand Down
189 changes: 189 additions & 0 deletions stacks-core/src/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,192 @@ impl Codec for Script {
Ok(Self::from(buffer))
}
}

#[cfg(test)]
mod tests {
use std::{io::Cursor, str::FromStr};

use bdk::bitcoin::{
blockdata::{
opcodes::all::{OP_CHECKSIG, OP_DUP, OP_EQUALVERIFY, OP_HASH160},
script::Builder,
},
secp256k1::{Message, Secp256k1, SecretKey},
Amount, PublicKey,
};

use crate::StacksError;

use super::*;

#[test]
fn should_serialize_amount() -> anyhow::Result<()> {
let amount = Amount::from_sat(10_000);
let mut serialized_amount = vec![];

amount.serialize(&mut serialized_amount)?;

assert_eq!(serialized_amount, hex::decode("0000000000002710")?);

Ok(())
}

#[test]
fn should_deserialize_amount() -> anyhow::Result<()> {
let mut serialized_amount =
Cursor::new(hex::decode("0000000000002710")?);

let deserialized_amount = Amount::deserialize(&mut serialized_amount)?;

assert_eq!(deserialized_amount.to_sat(), 10_000);

Ok(())
}

#[test]
fn should_serialize_recoverable_signature() -> anyhow::Result<()> {
let signature = get_recoverable_signature()?;
let mut serialized_signature = vec![];

signature.serialize(&mut serialized_signature)?;

assert_eq!(serialized_signature, hex::decode("0119874ebfb457c08cedb5ebf01fe13bf4b6ac216b6f4044763ad95a69022bf1ba3cdba26d7ebb695a7144c8de4ba672dddfc602ffa9e62a745d8f7e4206ae6a93")?);

Ok(())
}

#[test]
fn should_deserialize_recoverable_signature() -> anyhow::Result<()> {
let mut serialized_signature = Cursor::new(
hex::decode("0119874ebfb457c08cedb5ebf01fe13bf4b6ac216b6f4044763ad95a69022bf1ba3cdba26d7ebb695a7144c8de4ba672dddfc602ffa9e62a745d8f7e4206ae6a93")?
);

let signature =
RecoverableSignature::deserialize(&mut serialized_signature)?;

let expected_signature = get_recoverable_signature()?;

assert_eq!(signature, expected_signature);

Ok(())
}

#[test]
fn should_fail_deserialize_recoverable_signature_with_invalid_id(
) -> anyhow::Result<()> {
let mut invalid_serialized_signature = Cursor::new(vec![4]);

let result = RecoverableSignature::deserialize(
&mut invalid_serialized_signature,
);

match result {
Err(StacksError::CodecError(_)) => Ok(()),
Err(e) => {
panic!("Expected invalid recovery ID error, but got {:?}", e)
}
Ok(_) => panic!("Expected invalid recovery ID error, but got Ok"),
}
CAGS295 marked this conversation as resolved.
Show resolved Hide resolved
}

#[test]
fn should_fail_deserialize_recoverable_signature_with_invalid_signature(
) -> anyhow::Result<()> {
let mut invalid_serialized_signature = vec![0; 65];

invalid_serialized_signature[0] = 1;

for i in 1..65 {
invalid_serialized_signature[i] = 255;
}

let result = RecoverableSignature::deserialize(&mut Cursor::new(
invalid_serialized_signature,
));

match result {
Err(StacksError::CodecError(_)) => Ok(()),
Err(e) => panic!("Expected invalid signature error, got {:?}", e),
Ok(_) => panic!("Expected invalid signature error, but got Ok"),
}
}

#[test]
fn should_serialize_u64() -> anyhow::Result<()> {
let mut serialized_u64 = vec![];

10_000u64.serialize(&mut serialized_u64)?;

assert_eq!(serialized_u64, hex::decode("0000000000002710")?);

Ok(())
}

#[test]
fn should_deserialize_u64() -> anyhow::Result<()> {
let mut serialized_u64 = Cursor::new(hex::decode("0000000000002710")?);

let deserialized_u64 = u64::deserialize(&mut serialized_u64)?;

assert_eq!(deserialized_u64, 10_000u64);

Ok(())
}

#[test]
fn should_serialize_script() -> anyhow::Result<()> {
let mut serialized_script = vec![];
let script = get_script()?;

script.serialize(&mut serialized_script)?;

assert_eq!(serialized_script, hex::decode("76a921023030cf3cd56ee3931a8fd0f59fa45920b39f6c2f033f6ee0cd714239d48d11ac88ac")?);

Ok(())
}

#[test]
fn should_deserialize_script() -> anyhow::Result<()> {
let mut serialized_script = Cursor::new(hex::decode("76a921023030cf3cd56ee3931a8fd0f59fa45920b39f6c2f033f6ee0cd714239d48d11ac88ac")?);

let deserialized_script = Script::deserialize(&mut serialized_script)?;
let expected_script = get_script()?;

assert_eq!(deserialized_script, expected_script);

Ok(())
}

fn get_recoverable_signature() -> anyhow::Result<RecoverableSignature> {
let secp = Secp256k1::new();

let secret_key_bytes = hex::decode(
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
)?;

let secret_key = SecretKey::from_slice(&secret_key_bytes)?;

let message = Message::from_slice(&mut hex::decode(
"1bf9ad7ce49adf6cbc707a689b6e17653151e95c1cd8a53f9fce54d3d51a2a24",
)?)?;

let recoverable_signature =
secp.sign_ecdsa_recoverable(&message, &secret_key);

Ok(recoverable_signature)
}

fn get_script() -> anyhow::Result<Script> {
let public_key = PublicKey::from_str("023030cf3cd56ee3931a8fd0f59fa45920b39f6c2f033f6ee0cd714239d48d11ac")?;

let script = Builder::new()
.push_opcode(OP_DUP)
.push_opcode(OP_HASH160)
.push_key(&public_key)
.push_opcode(OP_EQUALVERIFY)
.push_opcode(OP_CHECKSIG)
.into_script();

Ok(script)
}
}