Rename Serializable::hash() to Serializable::bitcoin_hash()
We were conflicting with the Rust stdlib trait Hash, which is used by various datastructures which need a general hash. Also implement Hash for Sha256dHash so that we can use bitcoin hashes as keys for such data structures.
This commit is contained in:
parent
a3846965e3
commit
54e4ea4586
|
@ -101,7 +101,7 @@ impl BlockHeader {
|
|||
if target != required_target {
|
||||
return Err(SpvBadTarget);
|
||||
}
|
||||
let ref hash = self.hash().as_uint256();
|
||||
let ref hash = self.bitcoin_hash().as_uint256();
|
||||
if hash <= target { Ok(()) } else { Err(SpvBadProofOfWork) }
|
||||
}
|
||||
|
||||
|
|
|
@ -106,8 +106,8 @@ impl Serializable for BlockchainNode {
|
|||
|
||||
// Override Serialize::hash to return the blockheader hash, since the
|
||||
// hash of the node itself is pretty much meaningless.
|
||||
fn hash(&self) -> Sha256dHash {
|
||||
self.block.header.hash()
|
||||
fn bitcoin_hash(&self) -> Sha256dHash {
|
||||
self.block.header.bitcoin_hash()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,7 +186,7 @@ impl Serializable for Blockchain {
|
|||
}
|
||||
|
||||
// Check that "genesis" is the genesis
|
||||
if (*scan).block.header.hash() != genesis_hash {
|
||||
if (*scan).bitcoin_hash() != genesis_hash {
|
||||
return Err(IoError {
|
||||
kind: OtherIoError,
|
||||
desc: "best tip did not link back to genesis",
|
||||
|
@ -225,7 +225,7 @@ impl Iterator<Sha256dHash> for LocatorHashIter {
|
|||
if self.index.is_null() {
|
||||
return None;
|
||||
}
|
||||
let ret = Some(unsafe { (*self.index).hash() });
|
||||
let ret = Some(unsafe { (*self.index).bitcoin_hash() });
|
||||
|
||||
// Rewind once (if we are at the genesis, this will set self.index to None)
|
||||
self.index = unsafe { (*self.index).prev };
|
||||
|
@ -357,7 +357,7 @@ impl Blockchain {
|
|||
/// Constructs a new blockchain
|
||||
pub fn new(network: Network) -> Blockchain {
|
||||
let genesis = genesis_block(network);
|
||||
let genhash = genesis.header.hash();
|
||||
let genhash = genesis.header.bitcoin_hash();
|
||||
let new_node = box BlockchainNode {
|
||||
total_work: Zero::zero(),
|
||||
required_difficulty: genesis.header.target(),
|
||||
|
@ -422,7 +422,7 @@ impl Blockchain {
|
|||
|
||||
/// Locates a block in the chain and overwrites its txdata
|
||||
pub fn add_txdata(&mut self, block: Block) -> BitcoinResult<()> {
|
||||
self.replace_txdata(&block.header.hash().as_uint256(), block.txdata, true)
|
||||
self.replace_txdata(&block.header.bitcoin_hash().as_uint256(), block.txdata, true)
|
||||
}
|
||||
|
||||
/// Locates a block in the chain and removes its txdata
|
||||
|
@ -453,7 +453,7 @@ impl Blockchain {
|
|||
// Check for multiple inserts (bitcoind from c9a09183 to 3c85d2ec doesn't
|
||||
// handle locator hashes properly and may return blocks multiple times,
|
||||
// and this may also happen in case of a reorg.
|
||||
if self.tree.lookup(&block.header.hash().as_uint256(), 256).is_some() {
|
||||
if self.tree.lookup(&block.header.bitcoin_hash().as_uint256(), 256).is_some() {
|
||||
return Err(DuplicateHash);
|
||||
}
|
||||
// Construct node, if possible
|
||||
|
@ -532,7 +532,7 @@ impl Blockchain {
|
|||
|
||||
// Insert the new block
|
||||
let raw_ptr = &*new_block as NodePtr;
|
||||
self.tree.insert(&new_block.block.header.hash().as_uint256(), 256, new_block);
|
||||
self.tree.insert(&new_block.block.header.bitcoin_hash().as_uint256(), 256, new_block);
|
||||
// Replace the best tip if necessary
|
||||
if unsafe { (*raw_ptr).total_work > (*self.best_tip).total_work } {
|
||||
self.set_best_tip(raw_ptr);
|
||||
|
@ -556,7 +556,7 @@ impl Blockchain {
|
|||
}
|
||||
}
|
||||
// Set best
|
||||
self.best_hash = unsafe { (*tip).hash() };
|
||||
self.best_hash = unsafe { (*tip).bitcoin_hash() };
|
||||
self.best_tip = tip;
|
||||
}
|
||||
|
||||
|
@ -632,8 +632,8 @@ mod tests {
|
|||
#[test]
|
||||
fn blockchain_serialize_test() {
|
||||
let empty_chain = Blockchain::new(Bitcoin);
|
||||
assert_eq!(empty_chain.best_tip().header.hash().serialize(),
|
||||
genesis_block(Bitcoin).header.hash().serialize());
|
||||
assert_eq!(empty_chain.best_tip().header.bitcoin_hash().serialize(),
|
||||
genesis_block(Bitcoin).header.bitcoin_hash().serialize());
|
||||
|
||||
let serial = empty_chain.serialize();
|
||||
assert_eq!(serial, empty_chain.serialize_iter().collect());
|
||||
|
@ -641,8 +641,8 @@ mod tests {
|
|||
let deserial: IoResult<Blockchain> = Serializable::deserialize(serial.iter().map(|n| *n));
|
||||
assert!(deserial.is_ok());
|
||||
let read_chain = deserial.unwrap();
|
||||
assert_eq!(read_chain.best_tip().header.hash().serialize(),
|
||||
genesis_block(Bitcoin).header.hash().serialize());
|
||||
assert_eq!(read_chain.best_tip().header.bitcoin_hash().serialize(),
|
||||
genesis_block(Bitcoin).header.bitcoin_hash().serialize());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ use blockdata::script::Script;
|
|||
use blockdata::transaction::{Transaction, TxOut, TxIn};
|
||||
use blockdata::block::{Block, BlockHeader};
|
||||
use util::misc::hex_bytes;
|
||||
use util::hash::{merkle_root, zero_hash};
|
||||
use util::hash::{MerkleRoot, zero_hash};
|
||||
use util::uint::Uint256;
|
||||
|
||||
pub static MAX_SEQUENCE: u32 = 0xFFFFFFFF;
|
||||
|
@ -86,7 +86,7 @@ pub fn genesis_block(network: Network) -> Block {
|
|||
header: BlockHeader {
|
||||
version: 1,
|
||||
prev_blockhash: zero_hash(),
|
||||
merkle_root: merkle_root(txdata.as_slice()),
|
||||
merkle_root: txdata.merkle_root(),
|
||||
time: 1231006505,
|
||||
bits: 0x1d00ffff,
|
||||
nonce: 2083236893
|
||||
|
@ -100,7 +100,7 @@ pub fn genesis_block(network: Network) -> Block {
|
|||
header: BlockHeader {
|
||||
version: 1,
|
||||
prev_blockhash: zero_hash(),
|
||||
merkle_root: merkle_root(txdata.as_slice()),
|
||||
merkle_root: txdata.merkle_root(),
|
||||
time: 1296688602,
|
||||
bits: 0x1d00ffff,
|
||||
nonce: 414098458
|
||||
|
@ -138,8 +138,8 @@ mod test {
|
|||
assert_eq!(gen.output[0].value, 50 * COIN_VALUE);
|
||||
assert_eq!(gen.lock_time, 0);
|
||||
|
||||
assert_eq!(gen.hash().serialize().iter().rev().map(|n| *n).collect::<Vec<u8>>(),
|
||||
hex_bytes("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b").unwrap());
|
||||
assert_eq!(gen.bitcoin_hash().le_hex_string(),
|
||||
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -153,7 +153,7 @@ mod test {
|
|||
assert_eq!(gen.header.time, 1231006505);
|
||||
assert_eq!(gen.header.bits, 0x1d00ffff);
|
||||
assert_eq!(gen.header.nonce, 2083236893);
|
||||
assert_eq!(gen.header.hash().le_hex_string(),
|
||||
assert_eq!(gen.header.bitcoin_hash().le_hex_string(),
|
||||
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f".to_string());
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ mod test {
|
|||
assert_eq!(gen.header.time, 1296688602);
|
||||
assert_eq!(gen.header.bits, 0x1d00ffff);
|
||||
assert_eq!(gen.header.nonce, 414098458);
|
||||
assert_eq!(gen.header.hash().le_hex_string(),
|
||||
assert_eq!(gen.header.bitcoin_hash().le_hex_string(),
|
||||
"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943".to_string());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,16 +91,15 @@ fn test_transaction() {
|
|||
assert_eq!(realtx.version, 1);
|
||||
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. (This is why we
|
||||
// have this crazy .iter().rev() thing going on in many hash-related tests.
|
||||
assert_eq!(realtx.input[0].prev_hash.as_slice().iter().rev().map(|n| *n).collect::<Vec<u8>>(),
|
||||
hex_bytes("ce9ea9f6f5e422c6a9dbcddb3b9a14d1c78fab9ab520cb281aa2a74a09575da1").unwrap());
|
||||
// as little-endian 256-bit numbers rather than as data strings.
|
||||
assert_eq!(realtx.input[0].prev_hash.le_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.hash().serialize().iter().rev().map(|n| *n).collect::<Vec<u8>>(),
|
||||
hex_bytes("a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7").unwrap());
|
||||
assert_eq!(realtx.bitcoin_hash().le_hex_string(),
|
||||
"a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ impl UtxoSet {
|
|||
// while the reference client won't, causing us to fork off the network.
|
||||
UtxoSet {
|
||||
tree: PatriciaTree::new(),
|
||||
last_hash: genesis_block(network).header.hash(),
|
||||
last_hash: genesis_block(network).header.bitcoin_hash(),
|
||||
spent_txos: Vec::from_elem(rewind_limit, vec![]),
|
||||
spent_idx: 0,
|
||||
n_utxos: 0
|
||||
|
@ -69,7 +69,7 @@ impl UtxoSet {
|
|||
|
||||
/// Add all the UTXOs of a transaction to the set
|
||||
fn add_utxos(&mut self, tx: &Transaction) -> bool {
|
||||
let txid = tx.hash();
|
||||
let txid = tx.bitcoin_hash();
|
||||
// Locate node if it's already there
|
||||
let mut new_node = ThinVec::with_capacity(tx.output.len() as u32);
|
||||
for (vout, txo) in tx.output.iter().enumerate() {
|
||||
|
@ -136,7 +136,7 @@ impl UtxoSet {
|
|||
|
||||
// Set the next hash immediately so that if anything goes wrong,
|
||||
// we can rewind from the point that we're at.
|
||||
self.last_hash = block.header.hash();
|
||||
self.last_hash = block.header.bitcoin_hash();
|
||||
let spent_idx = self.spent_idx as uint;
|
||||
self.spent_idx = (self.spent_idx + 1) % self.spent_txos.len() as u64;
|
||||
self.spent_txos.get_mut(spent_idx).clear();
|
||||
|
@ -165,11 +165,11 @@ impl UtxoSet {
|
|||
// dupes were noticed. See bitcoind commit `ab91bf39` and BIP30.
|
||||
// TODO: add a unit test for these blocks.
|
||||
if !self.add_utxos(tx) {
|
||||
let blockhash = block.header.hash().le_hex_string();
|
||||
let blockhash = block.header.bitcoin_hash().le_hex_string();
|
||||
if blockhash == "00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec".to_string() ||
|
||||
blockhash == "00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721".to_string() {
|
||||
// For these specific blocks, overwrite the old UTXOs.
|
||||
self.tree.delete(&tx.hash().as_uint128(), KEY_LEN);
|
||||
self.tree.delete(&tx.bitcoin_hash().as_uint128(), KEY_LEN);
|
||||
self.add_utxos(tx);
|
||||
} else {
|
||||
// Otherwise fail the block
|
||||
|
@ -185,7 +185,7 @@ impl UtxoSet {
|
|||
/// Unapply the transactions contained in a block
|
||||
pub fn rewind(&mut self, block: &Block) -> bool {
|
||||
// Make sure we are rewinding the latest block
|
||||
if self.last_hash != block.header.hash() {
|
||||
if self.last_hash != block.header.bitcoin_hash() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -200,7 +200,7 @@ impl UtxoSet {
|
|||
// Delete added txouts
|
||||
let mut skipped_genesis = false;
|
||||
for tx in block.txdata.iter() {
|
||||
let txhash = tx.hash();
|
||||
let txhash = tx.bitcoin_hash();
|
||||
for n in range(0, tx.output.len()) {
|
||||
// Just bomb out the whole transaction
|
||||
self.take_utxo(txhash, n as u32);
|
||||
|
@ -290,12 +290,12 @@ mod tests {
|
|||
for tx in new_block.txdata.iter() {
|
||||
empty_set.add_utxos(tx);
|
||||
}
|
||||
empty_set.last_hash = new_block.header.hash();
|
||||
empty_set.last_hash = new_block.header.bitcoin_hash();
|
||||
|
||||
// Check that all the UTXOs were added
|
||||
assert_eq!(empty_set.n_utxos(), 2);
|
||||
for tx in new_block.txdata.iter() {
|
||||
let hash = tx.hash();
|
||||
let hash = tx.bitcoin_hash();
|
||||
for (n, out) in tx.output.iter().enumerate() {
|
||||
let n = n as u32;
|
||||
assert_eq!(empty_set.get_utxo(hash, n), Some(&box out.clone()));
|
||||
|
@ -307,7 +307,7 @@ mod tests {
|
|||
assert!(!empty_set.update(&new_block));
|
||||
assert_eq!(empty_set.n_utxos(), 2);
|
||||
for tx in new_block.txdata.iter() {
|
||||
let hash = tx.hash();
|
||||
let hash = tx.bitcoin_hash();
|
||||
for (n, out) in tx.output.iter().enumerate() {
|
||||
let n = n as u32;
|
||||
assert_eq!(empty_set.get_utxo(hash, n), Some(&box out.clone()));
|
||||
|
@ -324,7 +324,7 @@ mod tests {
|
|||
// Check that all outputs are there
|
||||
let mut read_set = deserial.unwrap();
|
||||
for tx in new_block.txdata.iter() {
|
||||
let hash = tx.hash();
|
||||
let hash = tx.bitcoin_hash();
|
||||
|
||||
for (n, out) in tx.output.iter().enumerate() {
|
||||
let n = n as u32;
|
||||
|
@ -343,7 +343,7 @@ mod tests {
|
|||
assert!(read_again.rewind(&new_block));
|
||||
assert_eq!(read_again.n_utxos(), 0);
|
||||
for tx in new_block.txdata.iter() {
|
||||
let hash = tx.hash();
|
||||
let hash = tx.bitcoin_hash();
|
||||
|
||||
for n in range(0, tx.output.len()) {
|
||||
let n = n as u32;
|
||||
|
|
|
@ -98,7 +98,7 @@ pub trait Serializable {
|
|||
/// Read an object off the wire
|
||||
fn deserialize<I: Iterator<u8>>(iter: I) -> IoResult<Self>;
|
||||
/// Obtain a hash of the object
|
||||
fn hash(&self) -> Sha256dHash {
|
||||
fn bitcoin_hash(&self) -> Sha256dHash {
|
||||
Sha256dHash::from_data(self.serialize().as_slice())
|
||||
}
|
||||
/// Dump the object to a file
|
||||
|
|
|
@ -21,6 +21,8 @@ use core::cmp::min;
|
|||
use std::fmt;
|
||||
use std::io::{IoResult, IoError, InvalidInput};
|
||||
use std::mem::transmute;
|
||||
use std::hash::sip::SipState;
|
||||
use std::hash::Hash;
|
||||
|
||||
use crypto::digest::Digest;
|
||||
use crypto::sha2;
|
||||
|
@ -33,6 +35,16 @@ use util::uint::Uint256;
|
|||
/// A Bitcoin hash, 32-bytes, computed from x as SHA256(SHA256(x))
|
||||
pub struct Sha256dHash([u8, ..32]);
|
||||
|
||||
/// Allow this to be used as a key for Rust's HashMap et. al.
|
||||
impl Hash for Sha256dHash {
|
||||
fn hash(&self, state: &mut SipState) {
|
||||
let &Sha256dHash(ref data) = self;
|
||||
for ch in data.iter() {
|
||||
ch.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the all-zeroes "hash"
|
||||
pub fn zero_hash() -> Sha256dHash { Sha256dHash([0u8, ..32]) }
|
||||
|
||||
|
@ -148,12 +160,15 @@ impl fmt::Show for Sha256dHash {
|
|||
}
|
||||
}
|
||||
|
||||
//TODO: this should be an impl and the function have first parameter self.
|
||||
//See https://github.com/rust-lang/rust/issues/15060 for why this isn't so.
|
||||
//impl<T: Serializable> Vec<T> {
|
||||
/// Construct a merkle tree from a vector, with elements ordered as
|
||||
/// they were in the original vector, and return the merkle root.
|
||||
pub fn merkle_root<T: Serializable>(data: &[T]) -> Sha256dHash {
|
||||
/// Any collection of objects for which a merkle root makes sense to calculate
|
||||
pub trait MerkleRoot {
|
||||
/// Construct a merkle tree from a collection, with elements ordered as
|
||||
/// they were in the original collection, and return the merkle root.
|
||||
fn merkle_root(&self) -> Sha256dHash;
|
||||
}
|
||||
|
||||
impl<'a, T: Serializable> MerkleRoot for &'a [T] {
|
||||
fn merkle_root(&self) -> Sha256dHash {
|
||||
fn merkle_root(data: Vec<Sha256dHash>) -> Sha256dHash {
|
||||
// Base case
|
||||
if data.len() < 1 {
|
||||
|
@ -167,14 +182,21 @@ impl fmt::Show for Sha256dHash {
|
|||
for idx in range(0, (data.len() + 1) / 2) {
|
||||
let idx1 = 2 * idx;
|
||||
let idx2 = min(idx1 + 1, data.len() - 1);
|
||||
let to_hash = data[idx1].hash().serialize().append(data[idx2].hash().serialize().as_slice());
|
||||
next.push(to_hash.hash());
|
||||
let to_hash = data[idx1].bitcoin_hash().serialize()
|
||||
.append(data[idx2].bitcoin_hash().serialize().as_slice());
|
||||
next.push(to_hash.bitcoin_hash());
|
||||
}
|
||||
merkle_root(next)
|
||||
}
|
||||
merkle_root(data.iter().map(|obj| obj.hash()).collect())
|
||||
merkle_root(self.iter().map(|obj| obj.bitcoin_hash()).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl <T: Serializable> MerkleRoot for Vec<T> {
|
||||
fn merkle_root(&self) -> Sha256dHash {
|
||||
self.as_slice().merkle_root()
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
Loading…
Reference in New Issue