From edfc13f0ba2f4a0ab41039bedb37691be0681289 Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 21 Nov 2016 17:05:42 +0100 Subject: [PATCH] fixed interpreter OP_DUP operation, converting integers to hashes, added more traces --- Cargo.lock | 1 + crypto/src/lib.rs | 6 +++ message/src/common/inventory.rs | 4 +- primitives/src/hash.rs | 2 +- script/Cargo.toml | 3 +- script/src/interpreter.rs | 1 + script/src/lib.rs | 2 + script/src/stack.rs | 5 +-- verification/src/chain_verifier.rs | 61 ++++++++++++++---------------- 9 files changed, 45 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29703fb9..b0312df4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -594,6 +594,7 @@ dependencies = [ "bitcrypto 0.1.0", "chain 0.1.0", "keys 0.1.0", + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "primitives 0.1.0", "serialization 0.1.0", ] diff --git a/crypto/src/lib.rs b/crypto/src/lib.rs index be642861..f3eb994b 100644 --- a/crypto/src/lib.rs +++ b/crypto/src/lib.rs @@ -156,6 +156,7 @@ pub fn checksum(data: &[u8]) -> H32 { #[cfg(test)] mod tests { + use primitives::bytes::Bytes; use super::{ripemd160, sha1, sha256, dhash160, dhash256, checksum}; #[test] @@ -184,6 +185,11 @@ mod tests { let expected = "b6a9c8c230722b7c748331a8b450f05566dc7d0f".into(); let result = dhash160(b"hello"); assert_eq!(result, expected); + + let expected = "865c71bfc7e314709207ab9e7e205c6f8e453d08".into(); + let bytes: Bytes = "210292be03ed9475445cc24a34a115c641a67e4ff234ccb08cb4c5cea45caa526cb26ead6ead6ead6ead6eadac".into(); + let result = dhash160(&bytes); + assert_eq!(result, expected); } #[test] diff --git a/message/src/common/inventory.rs b/message/src/common/inventory.rs index 3ad5acbb..2c732ecd 100644 --- a/message/src/common/inventory.rs +++ b/message/src/common/inventory.rs @@ -77,7 +77,7 @@ mod tests { #[test] fn test_inventory_serialize() { - let expected = "020000000000000000000000000000000000000000000000000000000000000000000004".into(); + let expected = "020000000400000000000000000000000000000000000000000000000000000000000000".into(); let inventory = InventoryVector { inv_type: InventoryType::MessageBlock, @@ -89,7 +89,7 @@ mod tests { #[test] fn test_inventory_deserialize() { - let raw: Bytes = "020000000000000000000000000000000000000000000000000000000000000000000004".into(); + let raw: Bytes = "020000000400000000000000000000000000000000000000000000000000000000000000".into(); let expected = InventoryVector { inv_type: InventoryType::MessageBlock, diff --git a/primitives/src/hash.rs b/primitives/src/hash.rs index f520b3c2..5a31d685 100644 --- a/primitives/src/hash.rs +++ b/primitives/src/hash.rs @@ -50,7 +50,7 @@ macro_rules! impl_hash { impl From for $name { fn from(v: u8) -> Self { let mut result = Self::default(); - result.0[$size - 1] = v; + result.0[0] = v; result } } diff --git a/script/Cargo.toml b/script/Cargo.toml index aa5b34fa..9a1930ac 100644 --- a/script/Cargo.toml +++ b/script/Cargo.toml @@ -9,5 +9,4 @@ chain = { path = "../chain" } keys = { path = "../keys" } primitives = { path = "../primitives" } serialization = { path = "../serialization" } - - +log = "0.3" diff --git a/script/src/interpreter.rs b/script/src/interpreter.rs index 097a231d..12fc9a15 100644 --- a/script/src/interpreter.rs +++ b/script/src/interpreter.rs @@ -1895,3 +1895,4 @@ mod tests { assert_eq!(verify_script(&input, &output, &flags, &checker), Err(Error::NumberOverflow)); } } + diff --git a/script/src/lib.rs b/script/src/lib.rs index 832c2d52..09ba56c6 100644 --- a/script/src/lib.rs +++ b/script/src/lib.rs @@ -1,3 +1,5 @@ +#[macro_use] +extern crate log; extern crate bitcrypto as crypto; extern crate chain; extern crate keys; diff --git a/script/src/stack.rs b/script/src/stack.rs index 2217ab31..52a5d943 100644 --- a/script/src/stack.rs +++ b/script/src/stack.rs @@ -88,7 +88,7 @@ impl Stack { try!(self.require(i)); let mut j = i; while j > 0 { - let v = self.data[self.data.len() - j].clone(); + let v = self.data[self.data.len() - i].clone(); self.data.push(v); j -= 1; } @@ -263,9 +263,8 @@ mod tests { assert_eq!(stack.dup(2), Ok(())); assert_eq!(stack, vec![0, 0, 0, 0].into()); let mut stack: Stack = vec![0, 1].into(); - assert_eq!(stack.dup(1), Ok(())); assert_eq!(stack.dup(2), Ok(())); - assert_eq!(stack, vec![0, 1, 1, 1, 1].into()); + assert_eq!(stack, vec![0, 1, 0, 1].into()); } #[test] diff --git a/verification/src/chain_verifier.rs b/verification/src/chain_verifier.rs index 32e891d7..c8527686 100644 --- a/verification/src/chain_verifier.rs +++ b/verification/src/chain_verifier.rs @@ -121,15 +121,11 @@ impl ChainVerifier { for (input_index, input) in transaction.inputs().iter().enumerate() { let store_parent_transaction = self.store.transaction(&input.previous_output.hash); - let parent_transaction = match store_parent_transaction { - Some(ref tx) => tx, - None => { - match block.transactions.iter().filter(|t| t.hash() == input.previous_output.hash).nth(0) { - Some(tx) => tx, - None => { return Err(TransactionError::Inconclusive(input.previous_output.hash.clone())); }, - } - }, - }; + let parent_transaction = store_parent_transaction + .as_ref() + .or_else(|| block.transactions.iter().find(|t| t.hash() == input.previous_output.hash)) + .ok_or_else(|| TransactionError::Inconclusive(input.previous_output.hash.clone()))?; + if parent_transaction.outputs.len() <= input.previous_output.index as usize { return Err(TransactionError::Input(input_index)); } @@ -152,7 +148,9 @@ impl ChainVerifier { if self.skip_sig { continue; } if let Err(e) = verify_script(&input, &output, &flags, &checker) { - trace!(target: "verification", "transaction signature verification failure: {}", e); + trace!(target: "verification", "transaction signature verification failure: {:?}", e); + trace!(target: "verification", "input:\n{}", input); + trace!(target: "verification", "output:\n{}", output); // todo: log error here return Err(TransactionError::Signature(input_index)) } @@ -160,10 +158,8 @@ impl ChainVerifier { Ok(()) } -} -impl Verify for ChainVerifier { - fn verify(&self, block: &chain::Block) -> VerificationResult { + fn verify_block(&self, block: &chain::Block) -> VerificationResult { let hash = block.hash(); // There should be at least 1 transaction @@ -206,32 +202,21 @@ impl Verify for ChainVerifier { } // verify transactions (except coinbase) - let mut block_sigops = try!( - utils::transaction_sigops(&block.transactions()[0]) - .map_err(|e| Error::Transaction(1, TransactionError::SignatureMallformed(format!("{}", e)))) - ); + let mut block_sigops = utils::transaction_sigops(&block.transactions()[0]) + .map_err(|e| Error::Transaction(1, TransactionError::SignatureMallformed(e.to_string())))?; - for (idx, transaction) in block.transactions().iter().skip(1).enumerate() { + for (idx, transaction) in block.transactions().iter().enumerate().skip(1) { - block_sigops += try!( - utils::transaction_sigops(transaction) - .map_err(|e| Error::Transaction(idx+1, TransactionError::SignatureMallformed(format!("{}", e)))) - ); + block_sigops += utils::transaction_sigops(transaction) + .map_err(|e| Error::Transaction(idx, TransactionError::SignatureMallformed(e.to_string())))?; if block_sigops > MAX_BLOCK_SIGOPS { return Err(Error::MaximumSigops); } - try!(self.verify_transaction(block, transaction).map_err(|e| Error::Transaction(idx+1, e))); + try!(self.verify_transaction(block, transaction).map_err(|e| Error::Transaction(idx, e))); } - trace!( - target: "verification", "Block {} (transactons: {}, sigops: {}) verification finished", - &hash, - block.transactions().len(), - &block_sigops - ); - // todo: pre-process projected block number once verification is parallel! match self.store.accepted_location(block.header()) { None => { @@ -249,16 +234,28 @@ impl Verify for ChainVerifier { } } +impl Verify for ChainVerifier { + fn verify(&self, block: &chain::Block) -> VerificationResult { + let result = self.verify_block(block); + trace!( + target: "verification", "Block {} (transactions: {}) verification finished. Result {:?}", + block.hash().to_reversed_str(), + block.transactions().len(), + result, + ); + result + } +} + impl ContinueVerify for ChainVerifier { type State = usize; fn continue_verify(&self, block: &chain::Block, state: usize) -> VerificationResult { // verify transactions (except coinbase) - for (idx, transaction) in block.transactions().iter().skip(state-1).enumerate() { + for (idx, transaction) in block.transactions().iter().enumerate().skip(state - 1) { try!(self.verify_transaction(block, transaction).map_err(|e| Error::Transaction(idx, e))); } - let _parent = match self.store.block(BlockRef::Hash(block.header().previous_header_hash.clone())) { Some(b) => b, None => { return Ok(Chain::Orphan); }