Test outcome of encoding, not chunking
What changed, and why it matters
This commit is a test-only refactor. It changes how encoding is verified in unit tests: instead of checking the exact byte chunks an encoder produces one at a time, tests now only check the final concatenated byte output. It also deletes tests that poked at internal encoder details and updates documentation to say chunk sizes are not guaranteed. There is no change to production code behavior.
No security action required. Treat as normal code-quality/test-maintenance change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch modifies only test files and trait documentation in the rust-bitcoin consensus_encoding and primitives crates. It removes assertions on current_chunk()/advance() chunk boundaries and replaces them with helper checks (check_encoder, check_encode) that compare the full encoded byte stream. It deletes tests for exhausted-encoder safety and internal WitnessesEncoder switching logic. The only library code change is a doc comment on the Encoder trait clarifying that chunk sizes are implementation details and only the concatenated bytes are stable.
Changed components
consensus_encoding/src/encode/mod.rs (documentation only)consensus_encoding/tests/composition.rsconsensus_encoding/tests/encode.rsprimitives/src/block.rs (tests only)primitives/src/transaction.rs (tests only)primitives/src/witness.rs (tests only)primitives/tests/encoding.rsInspect captured patch +74 / −432
diff --git a/consensus_encoding/src/encode/mod.rs b/consensus_encoding/src/encode/mod.rs
index 6da3e2b5..c8e33220 100644
--- a/consensus_encoding/src/encode/mod.rs
+++ b/consensus_encoding/src/encode/mod.rs
@@ -68,6 +68,10 @@ pub trait Encode {
/// `current_chunk`, write it somewhere and, once fully written, try to advance the encoder.
/// Attempting to call any method after [`advance`](Self::advance) returned `false` or calling
/// `advance` before fully processing the chunks will lead to unspecified buggy behavior.
+///
+/// The callers MUST NOT assume that the encoder returns any particular size of the chunks. The
+/// implementors are allowed to change the sizes of the chunks as long as the concatenation of all
+/// the bytes returned stays the same.
pub trait Encoder {
/// Yields the current encoded byteslice.
///
diff --git a/consensus_encoding/tests/composition.rs b/consensus_encoding/tests/composition.rs
index 5bdbfa48..a6345ec5 100644
--- a/consensus_encoding/tests/composition.rs
+++ b/consensus_encoding/tests/composition.rs
@@ -3,8 +3,8 @@
//! Test composition of encoders and decoders.
use bitcoin_consensus_encoding::{
- ArrayDecoder, ArrayEncoder, BytesEncoder, Decode, Decoder, Decoder2, Decoder2Error, Decoder6,
- Encode, Encoder, Encoder2, Encoder3, Encoder6, UnexpectedEofError,
+ ArrayDecoder, ArrayEncoder, BytesEncoder, check_encoder, Decode, Decoder, Decoder2,
+ Decoder2Error, Decoder6, Encode, Encoder, Encoder2, Encoder3, Encoder6, UnexpectedEofError,
};
#[cfg(feature = "alloc")]
use bitcoin_consensus_encoding::{drain_to_vec, encode_to_vec};
@@ -79,6 +79,7 @@ impl Decode for CompositeData {
#[cfg(feature = "alloc")]
#[test]
+#[cfg(feature = "alloc")]
fn composition_chain() {
let original = CompositeData { first: [0x01, 0x02, 0x03, 0x04], second: [0x05, 0x06] };
let encoded_bytes = encode_to_vec(&original);
@@ -94,6 +95,7 @@ fn composition_chain() {
#[cfg(feature = "alloc")]
#[test]
+#[cfg(feature = "alloc")]
fn composition_nested() {
let data = b"abcdef";
let mut encoder6 = Encoder6::new(
@@ -312,13 +314,5 @@ fn empty_encoders() {
BytesEncoder::without_length_prefix(&bytes[2..]),
);
- assert_eq!(encoder.current_chunk(), &[1, 2][..]);
- assert!(encoder.advance());
-
- // Still have to advance over empty slice.
- assert!(encoder.current_chunk().is_empty());
- assert!(encoder.advance());
-
- assert_eq!(encoder.current_chunk(), &[3, 4][..]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &bytes);
}
diff --git a/consensus_encoding/tests/encode.rs b/consensus_encoding/tests/encode.rs
index e95a7611..eb213a10 100644
--- a/consensus_encoding/tests/encode.rs
+++ b/consensus_encoding/tests/encode.rs
@@ -6,7 +6,7 @@
use std::io::{Cursor, Write};
use bitcoin_consensus_encoding::{
- ArrayEncoder, ArrayRefEncoder, BytesEncoder, Encode, Encoder, Encoder2,
+ ArrayEncoder, ArrayRefEncoder, BytesEncoder, check_encoder, Encode, Encoder, Encoder2,
Encoder3, Encoder4, Encoder6, EncoderByteIter, ExactSizeEncoder, SliceEncoder,
};
@@ -168,12 +168,7 @@ fn encode_slice_encoder_mixed_empty_and_data() {
let mut encoder = SliceEncoder::without_length_prefix(slice);
- assert!(encoder.current_chunk().is_empty());
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[1, 2]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[3]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[1, 2, 3]);
}
#[test]
@@ -184,33 +179,19 @@ fn encode_encoder2_with_first_empty_encoder() {
let mut encoder = Encoder2::new(enc1, enc2);
- assert!(encoder.current_chunk().is_empty());
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[1, 2, 3]);
- assert!(!encoder.advance());
-}
-
-#[test]
-fn encode_encoder_advance_multiple_times_when_exhausted() {
- // Test that calling advance() multiple times on exhausted encoder is safe.
- let mut encoder = ArrayEncoder::<2>::without_length_prefix([10, 20]);
-
- assert_eq!(encoder.current_chunk(), &[10, 20]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[1, 2, 3]);
}
#[test]
fn encode_option_encoder_some() {
let mut encoder = Some(ArrayEncoder::<3>::without_length_prefix([1, 2, 3]));
- assert_eq!(encoder.current_chunk(), &[1, 2, 3]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[1, 2, 3]);
}
#[test]
fn encode_option_encoder_none() {
let mut encoder: Option<ArrayEncoder<3>> = None;
- assert!(encoder.current_chunk().is_empty());
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[]);
}
#[test]
@@ -219,20 +200,16 @@ fn encode_array_with_data() {
let test_array = TestArray([1u8, 2, 3, 4]);
let mut encoder = test_array.encoder();
assert_eq!(encoder.len(), 4);
- assert!(!encoder.is_empty());
- assert_eq!(encoder.current_chunk(), &[1u8, 2, 3, 4][..]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[1u8, 2, 3, 4]);
}
#[test]
fn encode_empty_array() {
- // Empty array should have one empty chunk, then exhausted.
+ // Empty array should have empty encoding
let test_array = TestArray([]);
let mut encoder = test_array.encoder();
assert_eq!(encoder.len(), 0);
- assert!(encoder.is_empty());
- assert!(encoder.current_chunk().is_empty());
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[]);
}
#[test]
@@ -241,9 +218,7 @@ fn encode_array_ref_with_data() {
let data = [1u8, 2, 3, 4];
let mut encoder = ArrayRefEncoder::without_length_prefix(&data);
assert_eq!(encoder.len(), 4);
- assert!(!encoder.is_empty());
- assert_eq!(encoder.current_chunk(), &[1u8, 2, 3, 4][..]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[1u8, 2, 3, 4]);
}
#[test]
@@ -252,9 +227,7 @@ fn encode_empty_array_ref() {
let data = [];
let mut encoder = ArrayRefEncoder::without_length_prefix(&data);
assert_eq!(encoder.len(), 0);
- assert!(encoder.is_empty());
- assert!(encoder.current_chunk().is_empty());
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[]);
}
#[test]
@@ -265,10 +238,7 @@ fn encode_byte_slice_without_prefix() {
let mut encoder = test_bytes.encoder();
assert_eq!(encoder.len(), 3);
- assert!(!encoder.is_empty());
-
- assert_eq!(encoder.current_chunk(), &[1u8, 2, 3][..]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[1, 2, 3]);
}
#[test]
@@ -279,10 +249,7 @@ fn encode_empty_byte_slice_without_prefix() {
let mut encoder = test_bytes.encoder();
assert_eq!(encoder.len(), 0);
- assert!(encoder.is_empty());
-
- assert!(encoder.current_chunk().is_empty());
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[]);
}
#[test]
@@ -291,10 +258,7 @@ fn encode_slice_with_elements() {
let slice = &[TestArray([0x34, 0x12, 0x00, 0x00]), TestArray([0x78, 0x56, 0x00, 0x00])];
let mut encoder = SliceEncoder::without_length_prefix(slice);
- assert_eq!(encoder.current_chunk(), &[0x34, 0x12, 0x00, 0x00][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x78, 0x56, 0x00, 0x00][..]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[0x34, 0x12, 0x00, 0x00, 0x78, 0x56, 0x00, 0x00]);
}
#[test]
@@ -303,7 +267,7 @@ fn encode_empty_slice() {
let slice: &[TestArray<4>] = &[];
let mut encoder = SliceEncoder::without_length_prefix(slice);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[]);
}
#[test]
@@ -312,9 +276,7 @@ fn encode_slice_with_zero_sized_arrays() {
let slice = &[TestArray([]), TestArray([])];
let mut encoder = SliceEncoder::without_length_prefix(slice);
- assert!(encoder.current_chunk().is_empty());
- // The slice advanced is optimized to skip over empty chunks.
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[]);
}
#[test]
@@ -325,12 +287,8 @@ fn encode_two_arrays() {
let mut encoder = Encoder2::new(enc1, enc2);
assert_eq!(encoder.len(), 4);
- assert!(!encoder.is_empty());
- assert_eq!(encoder.current_chunk(), &[1u8, 2][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[3u8, 4][..]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[1, 2, 3, 4]);
}
#[test]
@@ -340,13 +298,7 @@ fn encode_two_empty_arrays() {
let enc2 = TestArray([]).encoder();
let mut encoder = Encoder2::new(enc1, enc2);
- assert_eq!(encoder.len(), 0);
- assert!(encoder.is_empty());
-
- assert!(encoder.current_chunk().is_empty());
- assert!(encoder.advance());
- assert!(encoder.current_chunk().is_empty());
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[]);
}
#[test]
@@ -358,14 +310,7 @@ fn encode_three_arrays() {
let mut encoder = Encoder3::new(enc1, enc2, enc3);
assert_eq!(encoder.len(), 6);
- assert!(!encoder.is_empty());
-
- assert_eq!(encoder.current_chunk(), &[1u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[2u8, 3u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[4u8, 5u8, 6u8][..]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[1, 2, 3, 4, 5, 6]);
}
#[test]
@@ -378,16 +323,7 @@ fn encode_four_arrays() {
let mut encoder = Encoder4::new(enc1, enc2, enc3, enc4);
assert_eq!(encoder.len(), 4);
- assert!(!encoder.is_empty());
-
- assert_eq!(encoder.current_chunk(), &[0x10][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x20][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x30][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x40][..]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[0x10, 0x20, 0x30, 0x40]);
}
#[test]
@@ -402,20 +338,7 @@ fn encode_six_arrays() {
let mut encoder = Encoder6::new(enc1, enc2, enc3, enc4, enc5, enc6);
assert_eq!(encoder.len(), 6);
- assert!(!encoder.is_empty());
-
- assert_eq!(encoder.current_chunk(), &[0x01][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x02][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x03][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x04][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x05][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x06][..]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06]);
}
#[test]
@@ -426,12 +349,7 @@ fn encode_mixed_composition_with_byte_slices() {
let mut encoder = Encoder2::new(enc1, enc2);
assert_eq!(encoder.len(), 4);
- assert!(!encoder.is_empty());
-
- assert_eq!(encoder.current_chunk(), &[0xFF, 0xEE][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0xDD, 0xCC][..]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[0xFF, 0xEE, 0xDD, 0xCC]);
}
#[test]
@@ -443,14 +361,7 @@ fn encode_nested_composition() {
let mut encoder = Encoder3::new(enc1, enc2, enc3);
assert_eq!(encoder.len(), 4);
- assert!(!encoder.is_empty());
-
- assert!(encoder.current_chunk().is_empty());
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x42][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x43, 0x44, 0x45][..]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[0x42, 0x43, 0x44, 0x45]);
}
#[test]
@@ -461,12 +372,7 @@ fn encode_slice_with_array_composition() {
let array_enc = TestArray([0x20, 0x21]).encoder();
let mut encoder = Encoder2::new(slice_enc, array_enc);
- assert_eq!(encoder.current_chunk(), &[0x10, 0x11][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x12, 0x13][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x20, 0x21][..]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[0x10, 0x11, 0x12, 0x13, 0x20, 0x21]);
}
#[test]
@@ -477,14 +383,7 @@ fn encode_array_with_slice_composition() {
let slice_enc = SliceEncoder::without_length_prefix(slice);
let mut encoder = Encoder2::new(header, slice_enc);
- assert_eq!(encoder.current_chunk(), &[0xFF, 0xFE][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x01][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x02][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x03][..]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[0xFF, 0xFE, 0x01, 0x02, 0x03]);
}
#[test]
@@ -499,20 +398,7 @@ fn encode_multiple_slices_composition() {
let enc3 = SliceEncoder::without_length_prefix(slice3);
let mut encoder = Encoder3::new(enc1, enc2, enc3);
- assert_eq!(encoder.current_chunk(), &[0xA1][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0xA2][..]);
-
- // Skip the empty slice
- assert!(encoder.advance());
-
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0xC1][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0xC2][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0xC3][..]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[0xA1, 0xA2, 0xC1, 0xC2, 0xC3]);
}
#[test]
@@ -524,14 +410,7 @@ fn encode_complex_nested_structure() {
let footer = TestBytes(&[0xBE, 0xEF]).encoder();
let mut encoder = Encoder3::new(header, slice_enc, footer);
- assert_eq!(encoder.current_chunk(), &[0xDE, 0xAD][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x01, 0x02][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0x03, 0x04][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[0xBE, 0xEF][..]);
- assert!(!encoder.advance());
+ check_encoder(&mut encoder, &[0xDE, 0xAD, 0x01, 0x02, 0x03, 0x04, 0xBE, 0xEF]);
}
#[test]
diff --git a/primitives/src/block.rs b/primitives/src/block.rs
index 8b954842..40a2b395 100644
--- a/primitives/src/block.rs
+++ b/primitives/src/block.rs
@@ -1012,7 +1012,7 @@ mod tests {
#[cfg(feature = "alloc")]
use encoding::Decode as _;
- use encoding::{Decoder as _, Encode as _, Encoder as _};
+ use encoding::{check_encode, Decoder as _};
#[cfg(feature = "hex")]
use hex::hex;
#[cfg(feature = "alloc")]
@@ -1825,10 +1825,8 @@ mod tests {
#[test]
fn version_encoder_emits_consensus_bytes() {
let version = Version::from_consensus(123_456_789);
- let mut encoder = version.encoder();
- assert_eq!(encoder.current_chunk(), &version.to_consensus().to_le_bytes());
- assert!(!encoder.advance());
+ check_encode(&version, &version.to_consensus().to_le_bytes());
}
#[test]
diff --git a/primitives/src/transaction.rs b/primitives/src/transaction.rs
index 309e1128..1db769f5 100644
--- a/primitives/src/transaction.rs
+++ b/primitives/src/transaction.rs
@@ -1612,7 +1612,7 @@ mod tests {
#[cfg(feature = "std")]
use std::error::Error as _;
- use encoding::{Decode as _, Decoder as _, Encoder as _};
+ use encoding::{Decode as _, Decoder as _};
#[cfg(feature = "hex")]
use hex::hex;
@@ -2449,74 +2449,11 @@ mod tests {
assert_eq!(Wtxid::from(tx.clone()), tx.compute_wtxid());
}
- #[test]
- #[cfg(feature = "alloc")]
- fn witnesses_encoder_advance_switch_path() {
- let tx_in_1 = TxIn {
- previous_output: OutPoint { txid: Txid::from_byte_array([0xAA; 32]), vout: 0 },
- script_sig: ScriptSigBuf::new(),
- sequence: Sequence::MAX,
- witness: Witness::from_slice(&[&[0x01u8][..]]),
- };
-
- let empty = [].as_slice();
- let many = vec![empty; 253];
- let tx_in_2 = TxIn {
- previous_output: OutPoint { txid: Txid::from_byte_array([0xBB; 32]), vout: 1 },
- script_sig: ScriptSigBuf::new(),
- sequence: Sequence::MAX,
- witness: Witness::from_slice(&many),
- };
-
- let inputs = [tx_in_1, tx_in_2];
-
- let mut finished = inputs[0].witness.encoder();
- while finished.advance() {}
- assert!(!finished.advance());
- let expected = inputs[1].witness.encoder().current_chunk().to_vec();
- assert!(!expected.is_empty());
-
- let mut encoder = WitnessesEncoder { inputs: &inputs, cur_enc: Some(finished) };
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), expected.as_slice());
- }
-
#[test]
#[cfg(feature = "alloc")]
fn witnesses_encoder_empty_inputs() {
let mut encoder = WitnessesEncoder::new(&[]);
- assert!(!encoder.advance());
- }
-
- #[test]
- #[cfg(feature = "alloc")]
- fn witnesses_encoder_switches_to_next_input_with_nonempty_chunk() {
- let input_0 = TxIn {
- previous_output: OutPoint { txid: Txid::from_byte_array([0xAA; 32]), vout: 0 },
- script_sig: ScriptSigBuf::new(),
- sequence: Sequence::MAX,
- witness: Witness::default(),
- };
-
- let input_1 = TxIn {
- previous_output: OutPoint { txid: Txid::from_byte_array([0xBB; 32]), vout: 2 },
- script_sig: ScriptSigBuf::new(),
- sequence: Sequence::MAX,
- witness: Witness::from_slice(&[&[1u8][..]]),
- };
-
- let inputs = vec![input_0, input_1];
- let mut encoder = WitnessesEncoder::new(&inputs);
-
- let next = inputs[1].witness.encoder();
- assert!(!next.current_chunk().is_empty());
-
- let mut exhausted = inputs[0].witness.encoder();
- while exhausted.advance() {}
- encoder.cur_enc = Some(exhausted);
-
- let advanced = encoder.advance();
- assert!(advanced);
+ encoding::check_encoder(&mut encoder, &[]);
}
#[test]
diff --git a/primitives/src/witness.rs b/primitives/src/witness.rs
index 8978e3e3..a0dee273 100644
--- a/primitives/src/witness.rs
+++ b/primitives/src/witness.rs
@@ -1006,9 +1006,7 @@ mod test {
#[cfg(feature = "alloc")]
use encoding::Decode as _;
- #[cfg(feature = "alloc")]
- use encoding::Encode as _;
- use encoding::Encoder as _;
+ use encoding::check_encode;
use super::*;
@@ -1369,15 +1367,7 @@ mod test {
// Use FromIterator directly
let witness = Witness::from_iter(data);
- // Should have length prefix chunk, then the content slice, then exhausted.
- let mut encoder = witness.encoder();
-
- assert_eq!(encoder.current_chunk(), &[2u8][..]);
- assert!(encoder.advance());
-
- // We don't encode one element at a time, rather we encode the whole content slice at once.
- assert_eq!(encoder.current_chunk(), &[3u8, 1, 2, 3, 2, 4, 5][..]);
- assert!(!encoder.advance());
+ check_encode(&witness, &[2u8, 3u8, 1, 2, 3, 2, 4, 5]);
}
#[test]
diff --git a/primitives/tests/encoding.rs b/primitives/tests/encoding.rs
index e922e978..b856f7b7 100644
--- a/primitives/tests/encoding.rs
+++ b/primitives/tests/encoding.rs
@@ -13,7 +13,7 @@ use bitcoin_primitives::{
absolute, Amount, Block, BlockHash, BlockHeader, BlockTime, BlockVersion, CompactTarget,
ScriptPubKeyBuf, ScriptSigBuf, Sequence, Witness,
};
-use encoding::{Decode as _, Decoder as _, Encode as _, Encoder as _};
+use encoding::{check_encode, Decode as _, Decoder as _};
use hex::hex;
const TC_TXID_BYTES: [u8; 32] = [
@@ -28,6 +28,16 @@ const TC_ONE_SAT_BYTES: [u8; 8] = [1, 0, 0, 0, 0, 0, 0, 0];
const TC_SEGWIT_MARKER_AND_FLAG: [u8; 2] = [0, 1];
const TC_WITNESS_ELEM_LEN_AND_DATA: [u8; 4] = [3, 1, 2, 3];
+macro_rules! concat_slices {
+ ($($chunk:expr),*) => {
+ {
+ let mut result = Vec::new();
+ $(result.extend_from_slice($chunk);)*
+ result
+ }
+ }
+}
+
fn tc_out_point() -> OutPoint {
let s = "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20:1";
s.parse::<OutPoint>().unwrap()
@@ -77,55 +87,19 @@ fn transaction_encode_decode_roundtrip() {
#[test]
fn encode_out_point() {
let out_point = tc_out_point();
- let mut encoder = out_point.encoder();
-
- // The txid
- assert_eq!(encoder.current_chunk(), &TC_TXID_BYTES[..]);
- assert!(encoder.advance());
-
- // The vout
- assert_eq!(encoder.current_chunk(), &TC_VOUT_BYTES[..]);
- assert!(!encoder.advance());
+ check_encode(&out_point, &concat_slices!(&TC_TXID_BYTES, &TC_VOUT_BYTES));
}
#[test]
fn encode_tx_out() {
let out = tx_out();
- let mut encoder = out.encoder();
-
- // The amount.
- assert_eq!(encoder.current_chunk(), &TC_ONE_SAT_BYTES[..]);
- assert!(encoder.advance());
-
- // The script pubkey length prefix.
- assert_eq!(encoder.current_chunk(), &[3u8][..]);
- assert!(encoder.advance());
-
- // The script pubkey data.
- assert_eq!(encoder.current_chunk(), &TC_SCRIPT_BYTES[..]);
- assert!(!encoder.advance());
+ check_encode(&out, &concat_slices!(&TC_ONE_SAT_BYTES, &[3u8], &TC_SCRIPT_BYTES));
}
#[test]
fn encode_tx_in() {
let txin = segwit_tx_in();
- let mut encoder = txin.encoder();
-
- // The outpoint (same as tested above).
- assert_eq!(encoder.current_chunk(), &TC_TXID_BYTES[..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_VOUT_BYTES[..]);
- assert!(encoder.advance());
-
- // The script sig
- assert_eq!(encoder.current_chunk(), &[3u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_SCRIPT_BYTES[..]);
- assert!(encoder.advance());
-
- // The sequence
- assert_eq!(encoder.current_chunk(), &TC_SEQ_MAX_BYTES[..]);
- assert!(!encoder.advance());
+ check_encode(&txin, &concat_slices!(&TC_TXID_BYTES, &TC_VOUT_BYTES, &[3u8], &TC_SCRIPT_BYTES, &TC_SEQ_MAX_BYTES));
}
#[test]
@@ -137,49 +111,7 @@ fn encode_segwit_transaction() {
outputs: vec![tx_out()],
};
- let mut encoder = tx.encoder();
-
- // The version
- assert_eq!(encoder.current_chunk(), &[2u8, 0, 0, 0][..]);
- assert!(encoder.advance());
-
- // The segwit marker and flag
- assert_eq!(encoder.current_chunk(), &TC_SEGWIT_MARKER_AND_FLAG[..]);
- assert!(encoder.advance());
-
- // The input (same as tested above) but with vec length prefix.
- assert_eq!(encoder.current_chunk(), &[1u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_TXID_BYTES[..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_VOUT_BYTES[..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[3u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_SCRIPT_BYTES[..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_SEQ_MAX_BYTES[..]);
- assert!(encoder.advance());
-
- // The output (same as tested above) but with vec length prefix.
- assert_eq!(encoder.current_chunk(), &[1u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_ONE_SAT_BYTES[..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[3u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_SCRIPT_BYTES[..]);
- assert!(encoder.advance());
-
- // The witness
- assert_eq!(encoder.current_chunk(), &[1u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_WITNESS_ELEM_LEN_AND_DATA[..]);
- assert!(encoder.advance());
-
- // The lock time.
- assert_eq!(encoder.current_chunk(), &TC_LOCK_TIME_ZERO_BYTES[..]);
- assert!(!encoder.advance());
+ check_encode(&tx, &concat_slices!(&[2u8, 0, 0, 0], &TC_SEGWIT_MARKER_AND_FLAG, &[1u8], &TC_TXID_BYTES, &TC_VOUT_BYTES, &[3u8], &TC_SCRIPT_BYTES, &TC_SEQ_MAX_BYTES, &[1u8], &TC_ONE_SAT_BYTES, &[3u8], &TC_SCRIPT_BYTES, &[1u8], &TC_WITNESS_ELEM_LEN_AND_DATA, &TC_LOCK_TIME_ZERO_BYTES));
}
#[test]
@@ -194,45 +126,7 @@ fn encode_non_segwit_transaction() {
outputs: vec![tx_out()],
};
- let mut encoder = tx.encoder();
-
- // The version
- assert_eq!(encoder.current_chunk(), &[2u8, 0, 0, 0][..]);
- assert!(encoder.advance());
-
- // Advance past the optional segwit bytes encoder.
- assert!(encoder.advance());
-
- // The input (same as tested above) but with vec length prefix.
- assert_eq!(encoder.current_chunk(), &[1u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_TXID_BYTES[..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_VOUT_BYTES[..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[3u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_SCRIPT_BYTES[..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_SEQ_MAX_BYTES[..]);
- assert!(encoder.advance());
-
- // The output (same as tested above) but with vec length prefix.
- assert_eq!(encoder.current_chunk(), &[1u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_ONE_SAT_BYTES[..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[3u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_SCRIPT_BYTES[..]);
- assert!(encoder.advance());
-
- // Advance past the optional witnesses encoder.
- assert!(encoder.advance());
-
- // The lock time.
- assert_eq!(encoder.current_chunk(), &TC_LOCK_TIME_ZERO_BYTES[..]);
- assert!(!encoder.advance());
+ check_encode(&tx, &concat_slices!(&[2u8, 0, 0, 0], &[1u8], &TC_TXID_BYTES, &TC_VOUT_BYTES, &[3u8], &TC_SCRIPT_BYTES, &TC_SEQ_MAX_BYTES, &[1u8], &TC_ONE_SAT_BYTES, &[3u8], &TC_SCRIPT_BYTES, &TC_LOCK_TIME_ZERO_BYTES));
}
#[test]
@@ -256,83 +150,29 @@ fn encode_block() {
};
let block = Block::new_unchecked(header, vec![tx]);
- let mut encoder = block.encoder();
-
- // The block header, 6 encoders, 1 chunk per encoder.
-
- // The block version.
- assert_eq!(encoder.current_chunk(), &[2u8, 0, 0, 0][..]);
- assert!(encoder.advance());
- // The previous block's blockhash.
- assert_eq!(
- encoder.current_chunk(),
+ check_encode(&block, &concat_slices!(
+ // The block version.
+ &[2u8, 0, 0, 0],
+ // The previous block's blockhash.
&[
171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171,
171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171
- ][..]
- );
- assert!(encoder.advance());
- // The merkle root hash.
- assert_eq!(
- encoder.current_chunk(),
+ ],
&[
205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205,
205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205
- ][..]
- );
- assert!(encoder.advance());
- // The block time.
- assert_eq!(encoder.current_chunk(), &[80, 195, 137, 98][..]);
- assert!(encoder.advance());
- // The target (bits).
- assert_eq!(encoder.current_chunk(), &[239, 190, 0, 0][..]);
- assert!(encoder.advance());
- // The nonce.
- assert_eq!(encoder.current_chunk(), &[254, 202, 0, 0][..]);
- assert!(encoder.advance());
-
- // The transaction list length prefix.
- assert_eq!(encoder.current_chunk(), &[1u8][..]);
- assert!(encoder.advance());
-
- // The transaction (same as tested above).
-
- // The version
- assert_eq!(encoder.current_chunk(), &[2u8, 0, 0, 0][..]);
- assert!(encoder.advance());
- // The segwit marker and flag
- assert_eq!(encoder.current_chunk(), &TC_SEGWIT_MARKER_AND_FLAG[..]);
- assert!(encoder.advance());
- // The input (same as tested above) but with vec length prefix.
- assert_eq!(encoder.current_chunk(), &[1u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_TXID_BYTES[..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_VOUT_BYTES[..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[3u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_SCRIPT_BYTES[..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_SEQ_MAX_BYTES[..]);
- assert!(encoder.advance());
- // The output (same as tested above) but with vec length prefix.
- assert_eq!(encoder.current_chunk(), &[1u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_ONE_SAT_BYTES[..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &[3u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_SCRIPT_BYTES[..]);
- assert!(encoder.advance());
- // The witness
- assert_eq!(encoder.current_chunk(), &[1u8][..]);
- assert!(encoder.advance());
- assert_eq!(encoder.current_chunk(), &TC_WITNESS_ELEM_LEN_AND_DATA[..]);
- assert!(encoder.advance());
- // The lock time.
- assert_eq!(encoder.current_chunk(), &TC_LOCK_TIME_ZERO_BYTES[..]);
- assert!(!encoder.advance());
+ ],
+ // The block time.
+ &[80, 195, 137, 98],
+ // The target (bits).
+ &[239, 190, 0, 0],
+ // The nonce.
+ &[254, 202, 0, 0],
+ // The transaction list length prefix.
+ &[1u8],
+ // The transaction (same as tested above).
+ &[2u8, 0, 0, 0], &TC_SEGWIT_MARKER_AND_FLAG, &[1u8], &TC_TXID_BYTES, &TC_VOUT_BYTES, &[3u8], &TC_SCRIPT_BYTES, &TC_SEQ_MAX_BYTES, &[1u8], &TC_ONE_SAT_BYTES, &[3u8], &TC_SCRIPT_BYTES, &[1u8], &TC_WITNESS_ELEM_LEN_AND_DATA, &TC_LOCK_TIME_ZERO_BYTES
+ ));
}
#[test]
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.