From bf7368e7192e78106e3473c3699945c65532d6a2 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 29 Nov 2016 13:35:54 +0300 Subject: [PATCH] added tests for cmpctblock --- sync/src/compact_block_builder.rs | 55 ++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/sync/src/compact_block_builder.rs b/sync/src/compact_block_builder.rs index dd4c5079..78d54b61 100644 --- a/sync/src/compact_block_builder.rs +++ b/sync/src/compact_block_builder.rs @@ -19,6 +19,7 @@ pub fn build_compact_block(block: IndexedBlock, prefilled_transactions_indexes: let mut prefilled_transactions: Vec = Vec::with_capacity(prefilled_transactions_len); let mut prefilled_transactions_size: usize = 0; + let (key0, key1) = short_transaction_id_keys(nonce, block.header()); for (transaction_index, (transaction_hash, transaction)) in block.transactions().enumerate() { let transaction_size = transaction.serialized_size(); if prefilled_transactions_size + transaction_size < MAX_COMPACT_BLOCK_PREFILLED_SIZE @@ -29,7 +30,7 @@ pub fn build_compact_block(block: IndexedBlock, prefilled_transactions_indexes: transaction: transaction.clone(), }) } else { - short_ids.push(short_transaction_id(nonce, block.header(), transaction_hash)); + short_ids.push(short_transaction_id(key0, key1, transaction_hash)); } } @@ -41,7 +42,7 @@ pub fn build_compact_block(block: IndexedBlock, prefilled_transactions_indexes: } } -fn short_transaction_id(nonce: u64, block_header: &BlockHeader, transaction_hash: &H256) -> ShortTransactionID { +pub fn short_transaction_id_keys(nonce: u64, block_header: &BlockHeader) -> (u64, u64) { // Short transaction IDs are used to represent a transaction without sending a full 256-bit hash. They are calculated by: // 1) single-SHA256 hashing the block header with the nonce appended (in little-endian) let mut stream = Stream::new(); @@ -53,24 +54,68 @@ fn short_transaction_id(nonce: u64, block_header: &BlockHeader, transaction_hash // 64-bit integers from the above hash, respectively. let key0 = LittleEndian::read_u64(&block_header_with_nonce_hash[0..8]); let key1 = LittleEndian::read_u64(&block_header_with_nonce_hash[8..16]); + + (key0, key1) +} + +pub fn short_transaction_id(key0: u64, key1: u64, transaction_hash: &H256) -> ShortTransactionID { + // 2) Running SipHash-2-4 with the input being the transaction ID and the keys (k0/k1) set to the first two little-endian + // 64-bit integers from the above hash, respectively. let siphash_transaction_hash = siphash24(key0, key1, &**transaction_hash); // 3) Dropping the 2 most significant bytes from the SipHash output to make it 6 bytes. let mut siphash_transaction_hash_bytes = [0u8; 8]; LittleEndian::write_u64(&mut siphash_transaction_hash_bytes, siphash_transaction_hash); - siphash_transaction_hash_bytes[2..8].into() + siphash_transaction_hash_bytes[0..6].into() } #[cfg(test)] mod tests { + use std::collections::HashSet; + use chain::{BlockHeader, Transaction, ShortTransactionID}; + use message::common::{BlockHeaderAndIDs, PrefilledTransaction}; + use test_data; + use super::*; + #[test] fn short_transaction_id_is_correct() { - // TODO + // https://webbtc.com/tx/fa755807ab9f3ca8a9b25982570700f3f94bb0627f373893c3cfe79b5cf16def + let transaction: Transaction = "01000000015fe01688dd8ae4428e21835c0e1b7af571c4223658d94da0c123e6fd7399862a010000006b483045022100f9e6d1bd3c9f54dcc72405994ec9ac2795878dd0b3cfbdc52bed28c2737fbecc02201fd68deab17bfaef1626e232cc4488dc273ba6fa5d807712b111d017cb96e0990121021fff64d1a21ede90d77cafa35fe7621db8aa433d947267980b395c35d23bd87fffffffff021ea56f72000000001976a9146fae1c8e7a648fff905dfdac9b019d3e887d7e8f88ac80f0fa02000000001976a9147f29b567c7dd9fc59cd3a7f716914966cc91ffa188ac00000000".into(); + let transaction_hash = transaction.hash(); + // https://webbtc.com/block/000000000000000001582cb2307ac43f3b4b268f2a75d3581d0babd48df1c300 + let block_header: BlockHeader = "000000205a54771c6a1a2bcc8f3412184f319dc02f7258b56fd5060100000000000000001de7a03cefe565d11cdfa369f6ffe59b9368a257203726c9cc363d31b4e3c2ebca4f3c58d4e6031830ccfd80".into(); + let nonce = 13450019974716797918_u64; + let (key0, key1) = short_transaction_id_keys(nonce, &block_header); + let actual_id = short_transaction_id(key0, key1, &transaction_hash); + let expected_id: ShortTransactionID = "036e8b8b8f00".into(); + assert_eq!(expected_id, actual_id); } #[test] fn compact_block_is_built_correctly() { - // TODO + let block = test_data::block_builder().header().parent(test_data::genesis().hash()).build() + .transaction().output().value(10).build().build() + .transaction().output().value(20).build().build() + .transaction().output().value(30).build().build() + .build(); // genesis -> block + let prefilled: HashSet<_> = vec![1].into_iter().collect(); + let compact_block = build_compact_block(block.clone().into(), prefilled); + let (key0, key1) = short_transaction_id_keys(compact_block.nonce, &block.block_header); + let short_ids = vec![ + short_transaction_id(key0, key1, &block.transactions[0].hash()), + short_transaction_id(key0, key1, &block.transactions[2].hash()), + ]; + assert_eq!(compact_block, BlockHeaderAndIDs { + header: block.block_header.clone(), + nonce: compact_block.nonce, + short_ids: short_ids, + prefilled_transactions: vec![ + PrefilledTransaction { + index: 1, + transaction: block.transactions[1].clone(), + } + ], + }); } }