diff --git a/src/blockdata/constants.rs b/src/blockdata/constants.rs index 9380d1b..a9f8821 100644 --- a/src/blockdata/constants.rs +++ b/src/blockdata/constants.rs @@ -139,7 +139,7 @@ mod test { assert_eq!(gen.output[0].value, 50 * COIN_VALUE); assert_eq!(gen.lock_time, 0); - assert_eq!(gen.bitcoin_hash().le_hex_string(), + assert_eq!(gen.bitcoin_hash().be_hex_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string()); } @@ -149,12 +149,12 @@ mod test { assert_eq!(gen.header.version, 1); assert_eq!(gen.header.prev_blockhash.as_slice(), zero_hash().as_slice()); - assert_eq!(gen.header.merkle_root.le_hex_string(), + assert_eq!(gen.header.merkle_root.be_hex_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string()); assert_eq!(gen.header.time, 1231006505); assert_eq!(gen.header.bits, 0x1d00ffff); assert_eq!(gen.header.nonce, 2083236893); - assert_eq!(gen.header.bitcoin_hash().le_hex_string(), + assert_eq!(gen.header.bitcoin_hash().be_hex_string(), "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f".to_string()); } @@ -163,12 +163,12 @@ mod test { let gen = genesis_block(BitcoinTestnet); assert_eq!(gen.header.version, 1); assert_eq!(gen.header.prev_blockhash.as_slice(), zero_hash().as_slice()); - assert_eq!(gen.header.merkle_root.le_hex_string(), + assert_eq!(gen.header.merkle_root.be_hex_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string()); assert_eq!(gen.header.time, 1296688602); assert_eq!(gen.header.bits, 0x1d00ffff); assert_eq!(gen.header.nonce, 414098458); - assert_eq!(gen.header.bitcoin_hash().le_hex_string(), + assert_eq!(gen.header.bitcoin_hash().be_hex_string(), "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943".to_string()); } } diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 01fe1ff..ed5b5f5 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -111,13 +111,13 @@ mod tests { assert_eq!(realtx.input.len(), 1); // In particular this one is easy to get backward -- in bitcoin hashes are encoded // as little-endian 256-bit numbers rather than as data strings. - assert_eq!(realtx.input[0].prev_hash.le_hex_string(), + assert_eq!(realtx.input[0].prev_hash.be_hex_string(), "ce9ea9f6f5e422c6a9dbcddb3b9a14d1c78fab9ab520cb281aa2a74a09575da1".to_string()); assert_eq!(realtx.input[0].prev_index, 1); assert_eq!(realtx.output.len(), 1); assert_eq!(realtx.lock_time, 0); - assert_eq!(realtx.bitcoin_hash().le_hex_string(), + assert_eq!(realtx.bitcoin_hash().be_hex_string(), "a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string()); } } diff --git a/src/blockdata/utxoset.rs b/src/blockdata/utxoset.rs index 4b208a9..63a6b46 100644 --- a/src/blockdata/utxoset.rs +++ b/src/blockdata/utxoset.rs @@ -164,7 +164,7 @@ impl UtxoSet { // See bitcoind commit `ab91bf39` and BIP30. match self.add_utxos(tx) { Some(mut replace) => { - let blockhash = block.header.bitcoin_hash().le_hex_string(); + let blockhash = block.header.bitcoin_hash().be_hex_string(); if blockhash == "00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec".to_string() || blockhash == "00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721".to_string() { // For these specific blocks, overwrite the old UTXOs. diff --git a/src/util/hash.rs b/src/util/hash.rs index aab349e..c400cb0 100644 --- a/src/util/hash.rs +++ b/src/util/hash.rs @@ -108,13 +108,13 @@ impl Sha256dHash { from_bytes(self.as_slice()) } - /// Converts a hash to a Uint256, interpreting it as a little endian number. + /// Converts a hash to a little-endian Uint256 pub fn into_uint256(self) -> Uint256 { let Sha256dHash(data) = self; unsafe { Uint256(transmute(data)) } } - /// Converts a hash to a Uint128, interpreting it as a little endian number. + /// Converts a hash to a little-endian Uint128, using only the "low" bytes pub fn into_uint128(self) -> Uint128 { let Sha256dHash(data) = self; // TODO: this function won't work correctly on big-endian machines @@ -128,7 +128,7 @@ impl Sha256dHash { pub fn le_hex_string(&self) -> String { let &Sha256dHash(data) = self; let mut ret = String::with_capacity(64); - for i in range(0u, 32).rev() { + for i in range(0u, 32) { ret.push_char(from_digit((data[i] / 0x10) as uint, 16).unwrap()); ret.push_char(from_digit((data[i] & 0x0f) as uint, 16).unwrap()); } @@ -139,7 +139,7 @@ impl Sha256dHash { pub fn be_hex_string(&self) -> String { let &Sha256dHash(data) = self; let mut ret = String::with_capacity(64); - for i in range(0u, 32) { + for i in range(0u, 32).rev() { ret.push_char(from_digit((data[i] / 0x10) as uint, 16).unwrap()); ret.push_char(from_digit((data[i] & 0x0f) as uint, 16).unwrap()); } @@ -293,20 +293,32 @@ mod tests { use collections::bitv::from_bytes; use std::io::MemWriter; use std::str::from_utf8; - use serialize::Encodable; use serialize::json; + + use network::serialize::{serialize, deserialize}; use util::hash::Sha256dHash; use util::misc::hex_bytes; #[test] fn test_sha256d() { + // nb the 5df6... output is the one you get from sha256sum. this is the + // "little-endian" hex string since it matches the in-memory representation + // of a Uint256 (which is little-endian) after transmutation assert_eq!(Sha256dHash::from_data(&[]).as_slice(), hex_bytes("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456").unwrap().as_slice()); assert_eq!(Sha256dHash::from_data(&[]).le_hex_string(), + "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456".to_string()); + assert_eq!(Sha256dHash::from_data(&[]).be_hex_string(), "56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d".to_string()); - assert_eq!(Sha256dHash::from_data(b"TEST").as_slice(), - hex_bytes("d7bd34bfe44a18d2aa755a344fe3e6b06ed0473772e6dfce16ac71ba0b0a241c").unwrap().as_slice()); + } + + #[test] + fn test_consenus_encode_roundtrip() { + let hash = Sha256dHash::from_data(&[]); + let serial = serialize(&hash).unwrap(); + let deserial = deserialize(serial).unwrap(); + assert_eq!(hash, deserial); } #[test] diff --git a/src/util/patricia_tree.rs b/src/util/patricia_tree.rs index 3f57b9a..c06edc8 100644 --- a/src/util/patricia_tree.rs +++ b/src/util/patricia_tree.rs @@ -238,17 +238,18 @@ impl+Shl+Shr, V> PatriciaTree } match (tree.child_l.take(), tree.child_r.take()) { (Some(_), Some(_)) => unreachable!(), - (Some(consolidate), None) | (None, Some(consolidate)) => { - tree.data = consolidate.data; - tree.child_l = consolidate.child_l; - tree.child_r = consolidate.child_r; + (Some(box PatriciaTree { data, child_l, child_r, skip_prefix, skip_len }), None) | + (None, Some(box PatriciaTree { data, child_l, child_r, skip_prefix, skip_len })) => { + tree.data = data; + tree.child_l = child_l; + tree.child_r = child_r; let new_bit = if bit { let ret: K = One::one(); ret << (tree.skip_len as uint) } else { Zero::zero() }; tree.skip_prefix = tree.skip_prefix + new_bit + - (consolidate.skip_prefix << (1 + tree.skip_len as uint)); - tree.skip_len += 1 + consolidate.skip_len; + (skip_prefix << (1 + tree.skip_len as uint)); + tree.skip_len += 1 + skip_len; return (false, ret); } // No children means this node is deletable @@ -295,17 +296,18 @@ impl+Shl+Shr, V> PatriciaTree return (false, ret); } // One child? Consolidate - (bit, Some(consolidate), None) | (bit, None, Some(consolidate)) => { - tree.data = consolidate.data; - tree.child_l = consolidate.child_l; - tree.child_r = consolidate.child_r; + (bit, Some(box PatriciaTree { data, child_l, child_r, skip_prefix, skip_len }), None) | + (bit, None, Some(box PatriciaTree { data, child_l, child_r, skip_prefix, skip_len })) => { + tree.data = data; + tree.child_l = child_l; + tree.child_r = child_r; let new_bit = if bit { let ret: K = One::one(); ret << (tree.skip_len as uint) } else { Zero::zero() }; tree.skip_prefix = tree.skip_prefix + new_bit + - (consolidate.skip_prefix << (1 + tree.skip_len as uint)); - tree.skip_len += 1 + consolidate.skip_len; + (skip_prefix << (1 + tree.skip_len as uint)); + tree.skip_len += 1 + skip_len; return (false, ret); } // No children? Delete