diff --git a/src/blockdata/block.rs b/src/blockdata/block.rs index 3a7f0a0..bcde959 100644 --- a/src/blockdata/block.rs +++ b/src/blockdata/block.rs @@ -101,7 +101,7 @@ impl BlockHeader { if target != required_target { return Err(SpvBadTarget); } - let ref hash = self.bitcoin_hash().into_uint256(); + let ref hash = self.bitcoin_hash().into_le(); if hash <= target { Ok(()) } else { Err(SpvBadProofOfWork) } } diff --git a/src/blockdata/blockchain.rs b/src/blockdata/blockchain.rs index 91df7c9..c73ef6f 100644 --- a/src/blockdata/blockchain.rs +++ b/src/blockdata/blockchain.rs @@ -141,20 +141,20 @@ impl, E> ConsensusDecodable for Blockchain { let genesis_hash: Sha256dHash = try!(ConsensusDecodable::consensus_decode(d)); // Lookup best tip - let best = match tree.lookup(&best_hash.into_uint256(), 256) { + let best = match tree.lookup(&best_hash.into_le(), 256) { Some(node) => &**node as NodePtr, None => { return Err(d.error(format!("best tip {:x} not in tree", best_hash).as_slice())); } }; // Lookup genesis - if tree.lookup(&genesis_hash.into_uint256(), 256).is_none() { + if tree.lookup(&genesis_hash.into_le(), 256).is_none() { return Err(d.error(format!("genesis {:x} not in tree", genesis_hash).as_slice())); } // Reconnect all prev pointers let raw_tree = &tree as *const _; for node in tree.mut_iter() { - let hash = node.block.header.prev_blockhash.into_uint256(); + let hash = node.block.header.prev_blockhash.into_le(); let prevptr = match unsafe { (*raw_tree).lookup(&hash, 256) } { Some(node) => &**node as NodePtr, @@ -355,7 +355,7 @@ impl Blockchain { network: network, tree: { let mut pat = PatriciaTree::new(); - pat.insert(&genhash.into_uint256(), 256, new_node); + pat.insert(&genhash.into_le(), 256, new_node); pat }, best_hash: genhash, @@ -400,17 +400,17 @@ impl Blockchain { /// Looks up a block in the chain and returns the BlockchainNode containing it pub fn get_block<'a>(&'a self, hash: Sha256dHash) -> Option<&'a BlockchainNode> { - self.tree.lookup(&hash.into_uint256(), 256).map(|node| &**node) + self.tree.lookup(&hash.into_le(), 256).map(|node| &**node) } /// Locates a block in the chain and overwrites its txdata pub fn add_txdata(&mut self, block: Block) -> BitcoinResult<()> { - self.replace_txdata(&block.header.bitcoin_hash().into_uint256(), block.txdata, true) + self.replace_txdata(&block.header.bitcoin_hash().into_le(), block.txdata, true) } /// Locates a block in the chain and removes its txdata pub fn remove_txdata(&mut self, hash: Sha256dHash) -> BitcoinResult<()> { - self.replace_txdata(&hash.into_uint256(), vec![], false) + self.replace_txdata(&hash.into_le(), vec![], false) } /// Adds a block header to the chain @@ -430,13 +430,13 @@ impl Blockchain { if hash == chain.best_hash { Some(chain.best_tip) } else { - chain.tree.lookup(&hash.into_uint256(), 256).map(|boxptr| &**boxptr as NodePtr) + chain.tree.lookup(&hash.into_le(), 256).map(|boxptr| &**boxptr as NodePtr) } } // 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.bitcoin_hash().into_uint256(), 256).is_some() { + if self.tree.lookup(&block.header.bitcoin_hash().into_le(), 256).is_some() { return Err(DuplicateHash); } // Construct node, if possible @@ -515,7 +515,7 @@ impl Blockchain { // Insert the new block let raw_ptr = &*new_block as NodePtr; - self.tree.insert(&new_block.block.header.bitcoin_hash().into_uint256(), 256, new_block); + self.tree.insert(&new_block.block.header.bitcoin_hash().into_le(), 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); @@ -565,7 +565,7 @@ impl Blockchain { /// An iterator over all blocks in the chain starting from `start_hash` pub fn iter<'a>(&'a self, start_hash: Sha256dHash) -> BlockIter<'a> { - let start = match self.tree.lookup(&start_hash.into_uint256(), 256) { + let start = match self.tree.lookup(&start_hash.into_le(), 256) { Some(boxptr) => &**boxptr as NodePtr, None => RawPtr::null() }; @@ -577,7 +577,7 @@ impl Blockchain { /// An iterator over all blocks in reverse order to the genesis, starting with `start_hash` pub fn rev_iter<'a>(&'a self, start_hash: Sha256dHash) -> RevBlockIter<'a> { - let start = match self.tree.lookup(&start_hash.into_uint256(), 256) { + let start = match self.tree.lookup(&start_hash.into_le(), 256) { Some(boxptr) => &**boxptr as NodePtr, None => RawPtr::null() }; @@ -589,7 +589,7 @@ impl Blockchain { /// An iterator over all blocks -not- in the best chain, in reverse order, starting from `start_hash` pub fn rev_stale_iter<'a>(&'a self, start_hash: Sha256dHash) -> RevStaleBlockIter<'a> { - let start = match self.tree.lookup(&start_hash.into_uint256(), 256) { + let start = match self.tree.lookup(&start_hash.into_le(), 256) { Some(boxptr) => { // If we are already on the main chain, we have a dead iterator if boxptr.is_on_main_chain(self) { diff --git a/src/blockdata/utxoset.rs b/src/blockdata/utxoset.rs index fad3a86..6d438a3 100644 --- a/src/blockdata/utxoset.rs +++ b/src/blockdata/utxoset.rs @@ -112,7 +112,7 @@ impl UtxoSet { }; // Get the old value, if any (this is suprisingly possible, c.f. BIP30 // and the other comments in this file referring to it) - let ret = self.table.swap(txid.into_uint128(), new_node); + let ret = self.table.swap(txid.into_le().low_128(), new_node); if ret.is_none() { self.n_utxos += tx.output.len() as u64; } @@ -124,7 +124,7 @@ impl UtxoSet { // This whole function has awkward scoping thx to lexical borrow scoping :( let (ret, should_delete) = { // Locate the UTXO, failing if not found - let node = match self.table.find_mut(&txid.into_uint128()) { + let node = match self.table.find_mut(&txid.into_le().low_128()) { Some(node) => node, None => return None }; @@ -142,7 +142,7 @@ impl UtxoSet { // Delete the whole node if it is no longer being used if should_delete { - self.table.remove(&txid.into_uint128()); + self.table.remove(&txid.into_le().low_128()); } self.n_utxos -= if ret.is_some() { 1 } else { 0 }; @@ -152,7 +152,7 @@ impl UtxoSet { /// Get a reference to a UTXO in the set pub fn get_utxo<'a>(&'a self, txid: Sha256dHash, vout: u32) -> Option<&'a TxOut> { // Locate the UTXO, failing if not found - let node = match self.table.find(&txid.into_uint128()) { + let node = match self.table.find(&txid.into_le().low_128()) { Some(node) => node, None => return None }; @@ -317,7 +317,7 @@ impl UtxoSet { for ((txid, n), txo) in extract_vec.move_iter() { // Remove the tx's utxo list and patch the txo into place let new_node = - match self.table.pop(&txid.into_uint128()) { + match self.table.pop(&txid.into_le().low_128()) { Some(mut thinvec) => { let old_len = thinvec.len() as u32; if old_len < n + 1 { @@ -343,7 +343,7 @@ impl UtxoSet { } }; // Ram it back into the tree - self.table.insert(txid.into_uint128(), new_node); + self.table.insert(txid.into_le().low_128(), new_node); } } skipped_genesis = true; diff --git a/src/util/hash.rs b/src/util/hash.rs index 4b26753..9b356fe 100644 --- a/src/util/hash.rs +++ b/src/util/hash.rs @@ -145,20 +145,21 @@ impl Sha256dHash { /// Converts a hash to a little-endian Uint256 #[inline] - pub fn into_uint256(self) -> Uint256 { + pub fn into_le(self) -> Uint256 { let Sha256dHash(data) = self; - unsafe { Uint256(transmute(data)) } + let mut ret: [u64, ..4] = unsafe { transmute(data) }; + for x in ret.as_mut_slice().mut_iter() { *x = x.to_le(); } + Uint256(ret) } - /// Converts a hash to a little-endian Uint128, using only the "low" bytes + /// Converts a hash to a big-endian Uint256 #[inline] - pub fn into_uint128(self) -> Uint128 { - let Sha256dHash(data) = self; - // TODO: this function won't work correctly on big-endian machines - unsafe { Uint128(transmute([data[16], data[17], data[18], data[19], data[20], - data[21], data[22], data[23], data[24], data[25], - data[26], data[27], data[28], data[29], data[30], - data[31]])) } + pub fn into_be(self) -> Uint256 { + let Sha256dHash(mut data) = self; + data.reverse(); + let mut ret: [u64, ..4] = unsafe { transmute(data) }; + for x in ret.mut_iter() { *x = x.to_be(); } + Uint256(ret) } /// Converts a hash to a Hash32 by truncation @@ -384,5 +385,15 @@ mod tests { "\"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d\"".as_bytes()); assert_eq!(json::decode(from_utf8(res.as_slice()).unwrap()), Ok(hash)); } + + #[test] + fn test_sighash_single_vec() { + let one = Sha256dHash([1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0]); + assert_eq!(Some(one.into_le()), FromPrimitive::from_u64(1)); + assert_eq!(Some(one.into_le().low_128()), FromPrimitive::from_u64(1)); + } } diff --git a/src/util/patricia_tree.rs b/src/util/patricia_tree.rs index c06edc8..95e2bae 100644 --- a/src/util/patricia_tree.rs +++ b/src/util/patricia_tree.rs @@ -553,7 +553,7 @@ mod tests { let mut tree = PatriciaTree::new(); let mut hashes = vec![]; for i in range(0u32, 5000) { - let hash = Sha256dHash::from_data(&[(i / 0x100) as u8, (i % 0x100) as u8]).into_uint128(); + let hash = Sha256dHash::from_data(&[(i / 0x100) as u8, (i % 0x100) as u8]).into_le().low_128(); tree.insert(&hash, 250, i); hashes.push(hash); } @@ -594,7 +594,7 @@ mod tests { let mut hashes = vec![]; // Start by inserting a bunch of chunder for i in range(1u32, 500) { - let hash = Sha256dHash::from_data(&[(i / 0x100) as u8, (i % 0x100) as u8]).into_uint128(); + let hash = Sha256dHash::from_data(&[(i / 0x100) as u8, (i % 0x100) as u8]).into_le().low_128(); tree.insert(&hash, 128, i * 1000); hashes.push(hash); } @@ -626,7 +626,7 @@ mod tests { let mut data = Vec::from_elem(n_elems, None); // Start by inserting a bunch of stuff for i in range(0, n_elems) { - let hash = Sha256dHash::from_data(&[(i / 0x100) as u8, (i % 0x100) as u8]).into_uint128(); + let hash = Sha256dHash::from_data(&[(i / 0x100) as u8, (i % 0x100) as u8]).into_le().low_128(); tree.insert(&hash, 128, i); *data.get_mut(i) = Some(()); } @@ -648,7 +648,7 @@ mod tests { let mut data = Vec::from_elem(n_elems, None); // Start by inserting a bunch of stuff for i in range(0, n_elems) { - let hash = Sha256dHash::from_data(&[(i / 0x100) as u8, (i % 0x100) as u8]).into_uint128(); + let hash = Sha256dHash::from_data(&[(i / 0x100) as u8, (i % 0x100) as u8]).into_le().low_128(); tree.insert(&hash, 128, i); *data.get_mut(i) = Some(()); } @@ -674,7 +674,7 @@ mod tests { let mut tree = PatriciaTree::new(); let mut hashes = vec![]; for i in range(0u32, 5000) { - let hash = Sha256dHash::from_data(&[(i / 0x100) as u8, (i % 0x100) as u8]).into_uint128(); + let hash = Sha256dHash::from_data(&[(i / 0x100) as u8, (i % 0x100) as u8]).into_le().low_128(); tree.insert(&hash, 250, i); hashes.push(hash); } diff --git a/src/util/uint.rs b/src/util/uint.rs index 3946f36..e7b47ef 100644 --- a/src/util/uint.rs +++ b/src/util/uint.rs @@ -367,6 +367,13 @@ impl Uint256 { } } } + + /// Decay to a uint128 + #[inline] + pub fn low_128(&self) -> Uint128 { + let &Uint256(data) = self; + Uint128([data[0], data[1]]) + } } #[cfg(test)]