Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 0 additions & 2 deletions src/primitives/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ impl GenesisTxHashSpec {
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct TxConstructor {
pub previous_out: OutPoint,
pub signatures: Vec<Signature>,
pub pub_keys: Vec<PublicKey>,
pub address_version: Option<u64>,
}

Expand Down
102 changes: 102 additions & 0 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,105 @@ pub fn add_btreemap<E: Ord, T: Copy + std::ops::AddAssign>(
});
m1
}

/// A trait which indicates that it is possible to acquire a "placeholder" value
/// of a type, which can be used for test purposes.
#[cfg(test)]
pub trait Placeholder : Sized {
/// Gets a placeholder value of this type which can be used for test purposes.
fn placeholder() -> Self;

/// Gets an array of placeholder values of this type which can be used for test purposes.
fn placeholder_array<const N: usize>() -> [Self; N] {
core::array::from_fn(|_| Self::placeholder())
}
}

/// A trait which indicates that it is possible to acquire a "placeholder" value
/// of a type, which can be used for test purposes. These placeholder values are consistent
/// across program runs.
#[cfg(test)]
pub trait PlaceholderSeed: Sized + PartialEq {
/// Gets a dummy valid of this type which can be used for test purposes.
///
/// This allows acquiring multiple distinct placeholder values which are still consistent
/// between runs.
///
/// ### Arguments
///
/// * `seed_parts` - the parts of the seed for the placeholder value to obtain. Two placeholder
/// values generated from the same seed are guaranteed to be equal (even
/// across multiple test runs, so long as the value format doesn't change).
fn placeholder_seed_parts<'a>(seed_parts: impl IntoIterator<Item = &'a [u8]>) -> Self;

/// Gets a dummy valid of this type which can be used for test purposes.
///
/// This allows acquiring multiple distinct placeholder values which are still consistent
/// between runs.
///
/// ### Arguments
///
/// * `seed` - the seed for the placeholder value to obtain. Two placeholder
/// values generated from the same seed are guaranteed to be equal (even
/// across multiple test runs, so long as the value format doesn't change).
fn placeholder_seed(seed: impl AsRef<[u8]>) -> Self {
Self::placeholder_seed_parts([ seed.as_ref() ])
}

/// Gets a dummy valid of this type which can be used for test purposes.
///
/// This allows acquiring multiple distinct placeholder values which are still consistent
/// between runs.
///
/// ### Arguments
///
/// * `index` - the index of the placeholder value to obtain. Two placeholder values generated
/// from the same index are guaranteed to be equal (even across multiple test runs,
/// so long as the value format doesn't change).
fn placeholder_indexed(index: u64) -> Self {
Self::placeholder_seed_parts([ index.to_le_bytes().as_slice() ])
}

/// Gets an array of placeholder values of this type which can be used for test purposes.
fn placeholder_array_seed<const N: usize>(seed: impl AsRef<[u8]>) -> [Self; N] {
core::array::from_fn(|n| Self::placeholder_seed_parts(
[ seed.as_ref(), &(n as u64).to_le_bytes() ]
))
}

/// Gets an array of placeholder values of this type which can be used for test purposes.
fn placeholder_array_indexed<const N: usize>(base_index: u64) -> [Self; N] {
Self::placeholder_array_seed(base_index.to_le_bytes())
}
}

#[cfg(test)]
impl<T: PlaceholderSeed> Placeholder for T {
fn placeholder() -> Self {
<Self as PlaceholderSeed>::placeholder_seed_parts([])
}
}

/// Generates the given number of pseudorandom bytes based on the given seed.
///
/// This is intended to be used in tests, where random but reproducible placeholder values are often
/// required.
///
/// ### Arguments
///
/// * `seed_parts` - the parts of the seed, which will be concatenated to form the RNG seed
#[cfg(test)]
pub fn placeholder_bytes<'a, const N: usize>(
seed_parts: impl IntoIterator<Item = &'a [u8]>
) -> [u8; N] {
// Use Shake-256 to generate an arbitrarily large number of random bytes based on the given seed.
let mut shake256 = sha3::Shake256::default();
for slice in seed_parts {
sha3::digest::Update::update(&mut shake256, slice);
}
let mut reader = sha3::digest::ExtendableOutput::finalize_xof(shake256);

let mut res = [0u8; N];
sha3::digest::XofReader::read(&mut reader, &mut res);
res
}
120 changes: 39 additions & 81 deletions src/utils/script_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2634,43 +2634,37 @@ mod tests {
}

/// Util function to create p2pkh TxIns
fn create_multisig_tx_ins(tx_values: Vec<TxConstructor>, m: usize) -> Vec<TxIn> {
let mut tx_ins = Vec::new();

for entry in tx_values {
let mut new_tx_in = TxIn::new();
new_tx_in.script_signature = Script::multisig_validation(
m,
entry.pub_keys.len(),
entry.previous_out.t_hash.clone(),
entry.signatures,
entry.pub_keys,
);
new_tx_in.previous_out = Some(entry.previous_out);

tx_ins.push(new_tx_in);
}

tx_ins
fn create_multisig_tx_ins(tx_values: &[(OutPoint, &[Signature], &[PublicKey])], m: usize) -> Vec<TxIn> {
tx_values.iter()
.map(|(previous_out, signatures, pub_keys)| {
let mut new_tx_in = TxIn::new();
new_tx_in.script_signature = Script::multisig_validation(
m,
pub_keys.len(),
previous_out.t_hash.clone(),
signatures.to_vec(),
pub_keys.to_vec(),
);
new_tx_in.previous_out = Some(previous_out.clone());
new_tx_in
})
.collect()
}

/// Util function to create multisig member TxIns
fn create_multisig_member_tx_ins(tx_values: Vec<TxConstructor>) -> Vec<TxIn> {
let mut tx_ins = Vec::new();

for entry in tx_values {
let mut new_tx_in = TxIn::new();
new_tx_in.script_signature = Script::member_multisig(
entry.previous_out.t_hash.clone(),
entry.pub_keys[0],
entry.signatures[0],
);
new_tx_in.previous_out = Some(entry.previous_out);

tx_ins.push(new_tx_in);
}

tx_ins
fn create_multisig_member_tx_ins(tx_values: &[(OutPoint, Signature, PublicKey)]) -> Vec<TxIn> {
tx_values.iter()
.map(|(previous_out, signature, pub_key)| {
let mut new_tx_in = TxIn::new();
new_tx_in.script_signature = Script::member_multisig(
previous_out.t_hash.clone(),
pub_key.clone(),
signature.clone(),
);
new_tx_in.previous_out = Some(previous_out.clone());
new_tx_in
})
.collect()
}

#[test]
Expand Down Expand Up @@ -2732,14 +2726,9 @@ mod tests {
let t_hash = hex::encode(vec![0, 0, 0]);
let signature = sign::sign_detached(t_hash.as_bytes(), &sk);

let tx_const = TxConstructor {
previous_out: OutPoint::new(t_hash, 0),
signatures: vec![signature],
pub_keys: vec![pk],
address_version,
};
let tx_const = (OutPoint::new(t_hash, 0), signature, pk);

let tx_ins = create_multisig_member_tx_ins(vec![tx_const]);
let tx_ins = create_multisig_member_tx_ins(&[tx_const]);

assert!(&tx_ins[0].clone().script_signature.interpret());
}
Expand Down Expand Up @@ -2768,14 +2757,9 @@ mod tests {
let t_hash = hex::encode(vec![0, 0, 0]);
let signature = sign::sign_detached(t_hash.as_bytes(), &sk);

let tx_const = TxConstructor {
previous_out: OutPoint::new(t_hash, 0),
signatures: vec![signature],
pub_keys: vec![pk],
address_version,
};
let tx_const = (OutPoint::new(t_hash, 0), signature, pk);

let tx_ins = create_multisig_member_tx_ins(vec![tx_const]);
let tx_ins = create_multisig_member_tx_ins(&[tx_const]);

assert!(!&tx_ins[0].clone().script_signature.interpret());
}
Expand All @@ -2797,8 +2781,6 @@ mod tests {

let tx_const = TxConstructor {
previous_out: outpoint,
signatures: vec![],
pub_keys: vec![pk],
address_version,
};

Expand Down Expand Up @@ -2837,12 +2819,9 @@ mod tests {
};

let hash_to_sign = construct_tx_in_signable_hash(&outpoint);
let signature = sign::sign_detached(hash_to_sign.as_bytes(), &sk);

let tx_const = TxConstructor {
previous_out: outpoint,
signatures: vec![signature],
pub_keys: vec![second_pk],
address_version,
};

Expand Down Expand Up @@ -2882,12 +2861,9 @@ mod tests {
};

let hash_to_sign = construct_tx_in_signable_hash(&outpoint);
let signature = sign::sign_detached(hash_to_sign.as_bytes(), &sk);

let tx_const = TxConstructor {
previous_out: outpoint,
signatures: vec![signature],
pub_keys: vec![pk],
address_version,
};

Expand Down Expand Up @@ -2936,12 +2912,9 @@ mod tests {
};

let hash_to_sign = construct_tx_in_signable_hash(&outpoint);
let signature = sign::sign_detached(hash_to_sign.as_bytes(), &sk);

let tx_const = TxConstructor {
previous_out: outpoint,
signatures: vec![signature],
pub_keys: vec![pk],
address_version,
};

Expand Down Expand Up @@ -2996,14 +2969,9 @@ mod tests {
let first_sig = sign::sign_detached(check_data.as_bytes(), &first_sk);
let second_sig = sign::sign_detached(check_data.as_bytes(), &second_sk);

let tx_const = TxConstructor {
previous_out: OutPoint::new(check_data, 0),
signatures: vec![first_sig, second_sig],
pub_keys: vec![first_pk, second_pk, third_pk],
address_version,
};

let tx_ins = create_multisig_tx_ins(vec![tx_const], m);
let tx_ins = create_multisig_tx_ins(&[
(OutPoint::new(check_data, 0), &[first_sig, second_sig], &[first_pk, second_pk, third_pk]),
], m);

assert!(&tx_ins[0].script_signature.interpret());
}
Expand Down Expand Up @@ -3305,14 +3273,9 @@ mod tests {
let t_hash = hex::encode(vec![0, 0, 0]);
let signature = sign::sign_detached(t_hash.as_bytes(), &sk);

let tx_const = TxConstructor {
previous_out: OutPoint::new(t_hash, 0),
signatures: vec![signature],
pub_keys: vec![pk],
address_version,
};
let tx_const = (OutPoint::new(t_hash, 0), signature, pk);

let tx_ins = create_multisig_member_tx_ins(vec![tx_const]);
let tx_ins = create_multisig_member_tx_ins(&[tx_const]);

assert!(!&tx_ins[0].clone().script_signature.interpret());
}
Expand Down Expand Up @@ -3340,14 +3303,9 @@ mod tests {
let t_hash = hex::encode(vec![0, 0, 0]);
let signature = sign::sign_detached(t_hash.as_bytes(), &sk);

let tx_const = TxConstructor {
previous_out: OutPoint::new(t_hash, 0),
signatures: vec![signature],
pub_keys: vec![pk],
address_version,
};
let tx_const = (OutPoint::new(t_hash, 0), signature, pk);

let tx_ins = create_multisig_member_tx_ins(vec![tx_const]);
let tx_ins = create_multisig_member_tx_ins(&[tx_const]);

assert!(&tx_ins[0].clone().script_signature.interpret());
}
Expand Down
Loading