From f83f7a53adda34301213f05c607c7d69ba247423 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 12 Mar 2019 12:48:38 +0300 Subject: [PATCH 1/6] removed obsolete ConfigStore trait --- db/src/block_chain_db.rs | 22 +--------------------- storage/src/lib.rs | 2 +- storage/src/store.rs | 11 +---------- 3 files changed, 3 insertions(+), 32 deletions(-) diff --git a/db/src/block_chain_db.rs b/db/src/block_chain_db.rs index 54c58c49..75ed7a26 100644 --- a/db/src/block_chain_db.rs +++ b/db/src/block_chain_db.rs @@ -24,7 +24,7 @@ use kv::{ use storage::{ BlockRef, Error, BlockHeaderProvider, BlockProvider, BlockOrigin, TransactionMeta, IndexedBlockProvider, TransactionMetaProvider, TransactionProvider, TransactionOutputProvider, BlockChain, Store, - SideChainOrigin, ForkChain, Forkable, CanonStore, ConfigStore, BestBlock, NullifierTracker, + SideChainOrigin, ForkChain, Forkable, CanonStore, BestBlock, NullifierTracker, EpochTag, EpochRef, SproutTreeState, SaplingTreeState, TreeStateProvider, }; @@ -733,23 +733,3 @@ impl Store for BlockChainDatabase where T: KeyValueDatabase { self.block_header(self.best_block().hash.into()).expect("best block header should be in db; qed") } } - -impl ConfigStore for BlockChainDatabase where T: KeyValueDatabase { - fn consensus_fork(&self) -> Result, Error> { - match self.db.get(&Key::Configuration("consensus_fork")) - .map(KeyState::into_option) - .map(|x| x.and_then(Value::as_configuration)) { - Ok(Some(consensus_fork)) => String::from_utf8(consensus_fork.into()) - .map_err(|e| Error::DatabaseError(format!("{}", e))) - .map(Some), - Ok(None) => Ok(None), - Err(e) => Err(Error::DatabaseError(e.into())), - } - } - - fn set_consensus_fork(&self, consensus_fork: &str) -> Result<(), Error> { - let mut update = DBTransaction::new(); - update.insert(KeyValue::Configuration("consensus_fork", consensus_fork.as_bytes().into())); - self.db.write(update).map_err(Error::DatabaseError) - } -} diff --git a/storage/src/lib.rs b/storage/src/lib.rs index 83c34835..cb685864 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -40,7 +40,7 @@ pub use block_provider::{BlockHeaderProvider, BlockProvider, IndexedBlockProvide pub use block_ref::BlockRef; pub use duplex_store::{DuplexTransactionOutputProvider, NoopStore}; pub use error::Error; -pub use store::{AsSubstore, Store, SharedStore, CanonStore, ConfigStore}; +pub use store::{AsSubstore, Store, SharedStore, CanonStore}; pub use transaction_meta::TransactionMeta; pub use transaction_provider::{TransactionProvider, TransactionOutputProvider, TransactionMetaProvider}; pub use nullifier_tracker::NullifierTracker; diff --git a/storage/src/store.rs b/storage/src/store.rs index c378e306..68f70c49 100644 --- a/storage/src/store.rs +++ b/storage/src/store.rs @@ -6,19 +6,10 @@ use { TreeStateProvider, }; -pub trait CanonStore: Store + Forkable + ConfigStore { +pub trait CanonStore: Store + Forkable { fn as_store(&self) -> &Store; } -/// Configuration storage interface -pub trait ConfigStore { - /// get consensus_fork this database is configured for - fn consensus_fork(&self) -> Result, Error>; - - /// set consensus_fork this database is configured for - fn set_consensus_fork(&self, consensus_fork: &str) -> Result<(), Error>; -} - /// Blockchain storage interface pub trait Store: AsSubstore { /// get best block From 668dc9e6203ea7dfe77beeb319a287b282cf67b2 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 12 Mar 2019 13:09:48 +0300 Subject: [PATCH 2/6] update default verification edge --- network/src/network.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/network/src/network.rs b/network/src/network.rs index e3b973e1..802e77ae 100644 --- a/network/src/network.rs +++ b/network/src/network.rs @@ -81,7 +81,11 @@ impl Network { } pub fn default_verification_edge(&self) -> H256 { - self.genesis_block().hash() + match *self { + // block #410100, best checkpoint of zcashd as of 12.03.2019 + Network::Mainnet => H256::from_reversed_str("0000000002c565958f783a24a4ac17cde898ff525e75ed9baf66861b0b9fcada"), + _ => self.genesis_block().hash(), + } } } From 61a3aad36d898673d3d85fa670e9e9d6e70eadcc Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 12 Mar 2019 13:10:06 +0300 Subject: [PATCH 3/6] update README.md --- README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e1be8d9c..19830992 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ cargo test --all By default parity connects to Zcash seednodes. Full list is [here](./pzec/seednodes.rs). -To start syncing the main network, just start the client, passing selected fork flag. For example: +To start syncing the main network, just start the client. For example: ``` ./target/release/pzec @@ -121,17 +121,19 @@ To not print any syncing progress add `--quiet` flag: ## Importing zcashd database -It it is possible to import existing `bitcoind` database: + It it is possible to import existing `zcashd` database: -``` -# where $BITCOIND_DB is path to your bitcoind database, e.g., "/Users/user/Library/Application Support" -./target/release/pzec import "$BITCOIND_DB/Bitcoin/blocks" + ``` +# where $ZCASH_DB is path to your zcashd database. By default: +# on macOS: "/Users/user/Library/Application Support/Zcash" +# on Linux: "~/.zcash" +./target/release/pzec import "$ZCASH_DB/blocks" ``` -By default import verifies imported the blocks. You can disable this, by adding `--verification-level==none` flag. +By default import verifies imported the blocks. You can disable this, by adding `--verification-level=none` flag. ``` -./target/release/pzec import "#BITCOIND_DB/Bitcoin/blocks" --verification-level==none +./target/release/pzec import "$ZCASH_DB/blocks" --verification-level=none ``` ## Command line interface From ab18faa78f415539d3fe3beec5bb4d6ef340eb42 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 12 Mar 2019 13:11:14 +0300 Subject: [PATCH 4/6] updated JSON-RPC.md --- JSON-RPC.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/JSON-RPC.md b/JSON-RPC.md index 6518e16a..13f6747d 100644 --- a/JSON-RPC.md +++ b/JSON-RPC.md @@ -38,7 +38,7 @@ Get the peer count. ### Blockchain -The Parity-bitcoin `blockchain` data interface. +The Parity Zcash `blockchain` data interface. #### getbestblockhash @@ -84,7 +84,7 @@ Get statistics about the unspent transaction output set. ### Miner -The Parity-bitcoin `miner` data interface. +The Parity Zcash `miner` data interface. #### getblocktemplate @@ -94,7 +94,7 @@ Get block template for mining. ### Raw -The Parity-bitcoin `raw` data interface. +The Parity Zcash `raw` data interface. #### getrawtransaction From 095e8ec21a7bc4cfcb564463b5c0425110790315 Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 12 Mar 2019 13:35:10 +0300 Subject: [PATCH 5/6] removed bitcoin-cash specific opcodes --- miner/src/block_assembler.rs | 9 +- script/src/flags.rs | 85 --- script/src/interpreter.rs | 964 +------------------------ script/src/opcode.rs | 27 +- script/src/script.rs | 33 +- storage/src/store.rs | 2 +- verification/src/accept_block.rs | 5 +- verification/src/accept_transaction.rs | 23 +- verification/src/sigops.rs | 7 +- verification/src/verify_block.rs | 2 +- verification/src/verify_transaction.rs | 2 +- 11 files changed, 27 insertions(+), 1132 deletions(-) diff --git a/miner/src/block_assembler.rs b/miner/src/block_assembler.rs index 225a8aa5..efa78c4f 100644 --- a/miner/src/block_assembler.rs +++ b/miner/src/block_assembler.rs @@ -139,8 +139,6 @@ struct FittingTransactionsIterator<'a, T> { block_height: u32, /// New block time block_time: u32, - /// Are OP_CHECKDATASIG && OP_CHECKDATASIGVERIFY enabled for this block. - checkdatasig_active: bool, /// Size policy decides if transactions size fits the block block_size: SizePolicy, /// Sigops policy decides if transactions sigops fits the block @@ -161,14 +159,12 @@ impl<'a, T> FittingTransactionsIterator<'a, T> where T: Iterator Self { FittingTransactionsIterator { store: store, iter: iter, block_height: block_height, block_time: block_time, - checkdatasig_active, // reserve some space for header and transactions len field block_size: SizePolicy::new(BLOCK_HEADER_SIZE + 4, max_block_size, 1_000, 50), sigops: SizePolicy::new(0, max_block_sigops, 8, 50), @@ -210,7 +206,7 @@ impl<'a, T> Iterator for FittingTransactionsIterator<'a, T> where T: Iterator BlockAssembler<'a> { self.max_block_size, self.max_block_sigops, height, - time, - false); + time); for entry in tx_iter { // miner_fee is i64, but we can safely cast it to u64 // memory pool should restrict miner fee to be positive diff --git a/script/src/flags.rs b/script/src/flags.rs index 8c1269ef..5960061c 100644 --- a/script/src/flags.rs +++ b/script/src/flags.rs @@ -59,42 +59,6 @@ pub struct VerificationFlags { /// /// See BIP112 for details pub verify_checksequence: bool, - - /// Support OP_CAT opcode - pub verify_concat: bool, - - /// Support OP_SPLIT opcode - /// - /// This opcode replaces OP_SUBSTR => enabling both OP_SPLIT && OP_SUBSTR would be an error - pub verify_split: bool, - - /// Support OP_AND opcode - pub verify_and: bool, - - /// Support OP_OR opcode - pub verify_or: bool, - - /// Support OP_XOR opcode - pub verify_xor: bool, - - /// Support OP_DIV opcode - pub verify_div: bool, - - /// Support OP_MOD opcode - pub verify_mod: bool, - - /// Support OP_BIN2NUM opcode - /// - /// This opcode replaces OP_RIGHT => enabling both OP_BIN2NUM && OP_RIGHT would be an error - pub verify_bin2num: bool, - - /// Support OP_NUM2BIN opcode - /// - /// This opcode replaces OP_LEFT => enabling both OP_NUM2BIN && OP_LEFT would be an error - pub verify_num2bin: bool, - - /// Support OP_CHECKDATASIG and OP_CHECKDATASIGVERIFY opcodes. - pub verify_checkdatasig: bool, } impl VerificationFlags { @@ -138,53 +102,4 @@ impl VerificationFlags { self } - pub fn verify_concat(mut self, value: bool) -> Self { - self.verify_concat = value; - self - } - - pub fn verify_split(mut self, value: bool) -> Self { - self.verify_split = value; - self - } - - pub fn verify_and(mut self, value: bool) -> Self { - self.verify_and = value; - self - } - - pub fn verify_or(mut self, value: bool) -> Self { - self.verify_or = value; - self - } - - pub fn verify_xor(mut self, value: bool) -> Self { - self.verify_xor = value; - self - } - - pub fn verify_div(mut self, value: bool) -> Self { - self.verify_div = value; - self - } - - pub fn verify_mod(mut self, value: bool) -> Self { - self.verify_mod = value; - self - } - - pub fn verify_bin2num(mut self, value: bool) -> Self { - self.verify_bin2num = value; - self - } - - pub fn verify_num2bin(mut self, value: bool) -> Self { - self.verify_num2bin = value; - self - } - - pub fn verify_checkdatasig(mut self, value: bool) -> Self { - self.verify_checkdatasig = value; - self - } } diff --git a/script/src/interpreter.rs b/script/src/interpreter.rs index 8299733a..93f655b5 100644 --- a/script/src/interpreter.rs +++ b/script/src/interpreter.rs @@ -1,10 +1,9 @@ use std::{cmp, mem}; use bytes::Bytes; -use keys::{Message, Signature, Public}; +use keys::{Signature, Public}; use chain::constants::SEQUENCE_LOCKTIME_DISABLE_FLAG; use crypto::{sha1, sha256, dhash160, dhash256, ripemd160}; use sign::Sighash; -use script::MAX_SCRIPT_ELEMENT_SIZE; use { script, Script, Num, VerificationFlags, Opcode, Error, SignatureChecker, Stack }; @@ -31,25 +30,6 @@ fn check_signature( checker.check_signature(&signature, &public, script_code, hash_type) } -/// Helper function. -fn verify_signature( - checker: &mut SignatureChecker, - signature: Vec, - public: Vec, - message: Message, -) -> bool { - let public = match Public::from_slice(&public) { - Ok(public) => public, - _ => return false, - }; - - if signature.is_empty() { - return false; - } - - checker.verify_signature(&signature.into(), &public, &message.into()) -} - fn is_public_key(v: &[u8]) -> bool { match v.len() { 33 if v[0] == 2 || v[0] == 3 => true, @@ -351,7 +331,7 @@ pub fn eval_script( } } - if opcode.is_disabled(flags) { + if opcode.is_disabled() { return Err(Error::DisabledOpcode(opcode)); } @@ -464,115 +444,6 @@ pub fn eval_script( let value = (opcode as i32).wrapping_sub(Opcode::OP_1 as i32 - 1); stack.push(Num::from(value).to_bytes()); }, - Opcode::OP_CAT if flags.verify_concat => { - let mut value_to_append = stack.pop()?; - let value_to_update = stack.last_mut()?; - if value_to_update.len() + value_to_append.len() > script::MAX_SCRIPT_ELEMENT_SIZE { - return Err(Error::PushSize); - } - value_to_update.append(&mut value_to_append); - }, - // OP_SPLIT replaces OP_SUBSTR - Opcode::OP_SUBSTR if flags.verify_split => { - let n = Num::from_slice(&stack.pop()?, flags.verify_minimaldata, 4)?; - if n.is_negative() { - return Err(Error::InvalidStackOperation); - } - let n: usize = n.into(); - let splitted_value = { - let mut value_to_split = stack.last_mut()?; - if n > value_to_split.len() { - return Err(Error::InvalidSplitRange); - } - value_to_split.split_off(n) - }; - stack.push(splitted_value); - }, - Opcode::OP_AND if flags.verify_and => { - let mask = stack.pop()?; - let mask_len = mask.len(); - let value_to_update = stack.last_mut()?; - if mask_len != value_to_update.len() { - return Err(Error::InvalidOperandSize); - } - for (byte_to_update, byte_mask) in (*value_to_update).iter_mut().zip(mask.iter()) { - *byte_to_update = *byte_to_update & byte_mask; - } - }, - Opcode::OP_OR if flags.verify_or => { - let mask = stack.pop()?; - let mask_len = mask.len(); - let value_to_update = stack.last_mut()?; - if mask_len != value_to_update.len() { - return Err(Error::InvalidOperandSize); - } - for (byte_to_update, byte_mask) in (*value_to_update).iter_mut().zip(mask.iter()) { - *byte_to_update = *byte_to_update | byte_mask; - } - }, - Opcode::OP_XOR if flags.verify_xor => { - let mask = stack.pop()?; - let mask_len = mask.len(); - let value_to_update = stack.last_mut()?; - if mask_len != value_to_update.len() { - return Err(Error::InvalidOperandSize); - } - for (byte_to_update, byte_mask) in (*value_to_update).iter_mut().zip(mask.iter()) { - *byte_to_update = *byte_to_update ^ byte_mask; - } - }, - Opcode::OP_DIV if flags.verify_div => { - let v1 = Num::from_slice(&stack.pop()?, flags.verify_minimaldata, 4)?; - let v2 = Num::from_slice(&stack.pop()?, flags.verify_minimaldata, 4)?; - if v2.is_zero() { - return Err(Error::DivisionByZero); - } - stack.push((v1 / v2).to_bytes()); - }, - Opcode::OP_MOD if flags.verify_mod => { - let v1 = Num::from_slice(&stack.pop()?, flags.verify_minimaldata, 4)?; - let v2 = Num::from_slice(&stack.pop()?, flags.verify_minimaldata, 4)?; - if v2.is_zero() { - return Err(Error::DivisionByZero); - } - stack.push((v1 % v2).to_bytes()); - }, - // OP_BIN2NUM replaces OP_RIGHT - Opcode::OP_RIGHT if flags.verify_bin2num => { - let bin = stack.pop()?; - let n = Num::minimally_encode(&bin, 4)?; - stack.push(n.to_bytes()); - }, - // OP_NUM2BIN replaces OP_LEFT - Opcode::OP_LEFT if flags.verify_num2bin => { - let bin_size = Num::from_slice(&stack.pop()?, flags.verify_minimaldata, 4)?; - if bin_size.is_negative() || bin_size > MAX_SCRIPT_ELEMENT_SIZE.into() { - return Err(Error::PushSize); - } - - let bin_size: usize = bin_size.into(); - let num = Num::minimally_encode(&stack.pop()?, 4)?; - let mut num = num.to_bytes(); - - // check if we can fit number into array of bin_size length - if num.len() > bin_size { - return Err(Error::ImpossibleEncoding); - } - - // check if we need to extend binary repr with zero-bytes - if num.len() < bin_size { - let sign_byte = num.last_mut().map(|last_byte| { - let sign_byte = *last_byte & 0x80; - *last_byte = *last_byte & 0x7f; - sign_byte - }).unwrap_or(0x00); - - num.resize(bin_size - 1, 0x00); - num.push(sign_byte); - } - - stack.push(num); - }, Opcode::OP_CAT | Opcode::OP_SUBSTR | Opcode::OP_LEFT | Opcode::OP_RIGHT | Opcode::OP_INVERT | Opcode::OP_AND | Opcode::OP_OR | Opcode::OP_XOR | Opcode::OP_2MUL | Opcode::OP_2DIV | Opcode::OP_MUL | Opcode::OP_DIV | @@ -979,34 +850,6 @@ pub fn eval_script( Opcode::OP_VERNOTIF => { return Err(Error::DisabledOpcode(opcode)); }, - Opcode::OP_CHECKDATASIG | Opcode::OP_CHECKDATASIGVERIFY if flags.verify_checkdatasig => { - let pubkey = stack.pop()?; - let message = stack.pop()?; - let signature = stack.pop()?; - - check_signature_encoding(&signature, flags)?; - check_pubkey_encoding(&pubkey, flags)?; - - let signature: Vec = signature.into(); - let message_hash = sha256(&message); - let success = verify_signature(checker, signature.into(), pubkey.into(), message_hash); - match opcode { - Opcode::OP_CHECKDATASIG => { - if success { - stack.push(vec![1].into()); - } else { - stack.push(vec![0].into()); - } - }, - Opcode::OP_CHECKDATASIGVERIFY if !success => { - return Err(Error::CheckDataSigVerify); - }, - _ => {}, - } - }, - Opcode::OP_CHECKDATASIG | Opcode::OP_CHECKDATASIGVERIFY => { - return Err(Error::DisabledOpcode(opcode)); - }, } if stack.len() + altstack.len() > 1000 { @@ -1030,9 +873,6 @@ pub fn eval_script( mod tests { use bytes::Bytes; use chain::Transaction; - use crypto::sha256; - use keys::{KeyPair, Private, Message, Network}; - use script::MAX_SCRIPT_ELEMENT_SIZE; use { Opcode, Script, VerificationFlags, Builder, Error, Num, TransactionInputSigner, NoopSignatureChecker, TransactionSignatureChecker, Stack @@ -2100,804 +1940,4 @@ mod tests { let result = Ok(true); basic_test(&script, result, vec![vec![1].into()].into()); } - - - #[test] - fn op_cat_disabled_by_default() { - let script = Builder::default() - .push_data(&[1; 1]) - .push_data(&[1; 1]) - .push_opcode(Opcode::OP_CAT) - .into_script(); - let result = Err(Error::DisabledOpcode(Opcode::OP_CAT)); - basic_test_with_flags(&script, &VerificationFlags::default(), result, - vec![].into()); - } - - #[test] - fn op_cat_max_and_non_empty_succeeds() { - // maxlen_x empty OP_CAT → ok - let script = Builder::default() - .push_data(&[1; MAX_SCRIPT_ELEMENT_SIZE]) - .push_data(&[1; 0]) - .push_opcode(Opcode::OP_CAT) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_concat(true), result, - vec![vec![1; MAX_SCRIPT_ELEMENT_SIZE].into()].into()); - } - - #[test] - fn op_cat_max_and_non_empty_fails() { - // maxlen_x y OP_CAT → failure - let script = Builder::default() - .push_data(&[1; MAX_SCRIPT_ELEMENT_SIZE]) - .push_data(&[1; 1]) - .push_opcode(Opcode::OP_CAT) - .into_script(); - let result = Err(Error::PushSize); - basic_test_with_flags(&script, &VerificationFlags::default().verify_concat(true), result, - vec![].into()); - } - - #[test] - fn op_cat_large_and_large_fails() { - // large_x large_y OP_CAT → failure - let script = Builder::default() - .push_data(&[1; MAX_SCRIPT_ELEMENT_SIZE / 2 + 1]) - .push_data(&[1; MAX_SCRIPT_ELEMENT_SIZE / 2 + 1]) - .push_opcode(Opcode::OP_CAT) - .into_script(); - let result = Err(Error::PushSize); - basic_test_with_flags(&script, &VerificationFlags::default().verify_concat(true), result, - vec![].into()); - } - - #[test] - fn op_cat_empty_and_empty_succeeds() { - // OP_0 OP_0 OP_CAT → OP_0 - let script = Builder::default() - .push_opcode(Opcode::OP_0) - .push_opcode(Opcode::OP_0) - .push_opcode(Opcode::OP_CAT) - .into_script(); - let result = Ok(false); - basic_test_with_flags(&script, &VerificationFlags::default().verify_concat(true), result, - vec![Bytes::default()].into()); - } - - #[test] - fn op_cat_non_empty_and_empty_succeeds() { - // x OP_0 OP_CAT → x - let script = Builder::default() - .push_data(&[1; 1]) - .push_opcode(Opcode::OP_0) - .push_opcode(Opcode::OP_CAT) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_concat(true), result, - vec![vec![1; 1].into()].into()); - } - - #[test] - fn op_cat_empty_and_non_empty_succeeds() { - // OP_0 x OP_CAT → x - let script = Builder::default() - .push_opcode(Opcode::OP_0) - .push_data(&[1; 1]) - .push_opcode(Opcode::OP_CAT) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_concat(true), result, - vec![vec![1; 1].into()].into()); - } - - #[test] - fn op_cat_non_empty_and_non_empty_succeeds() { - // x y OP_CAT → concat(x,y) - let script = Builder::default() - .push_data(&[0x11]) - .push_data(&[0x22, 0x33]) - .push_opcode(Opcode::OP_CAT) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_concat(true), result, - vec![vec![0x11, 0x22, 0x33].into()].into()); - } - - #[test] - fn op_split_disabled_by_default() { - let script = Builder::default() - .push_data(&[0x11, 0x22]) - .push_num(1.into()) - .push_opcode(Opcode::OP_SUBSTR) - .into_script(); - let result = Err(Error::DisabledOpcode(Opcode::OP_SUBSTR)); - basic_test_with_flags(&script, &VerificationFlags::default(), result, - vec![].into()); - } - - #[test] - fn op_split_empty_at_zero_succeeds() { - // OP_0 0 OP_SPLIT -> OP_0 OP_0 - let script = Builder::default() - .push_opcode(Opcode::OP_0) - .push_num(0.into()) - .push_opcode(Opcode::OP_SUBSTR) - .into_script(); - let result = Ok(false); - basic_test_with_flags(&script, &VerificationFlags::default().verify_split(true), result, - vec![vec![0; 0].into(), vec![0; 0].into()].into()); - } - - #[test] - fn op_split_non_empty_at_zero_succeeds() { - // x 0 OP_SPLIT -> OP_0 x - let script = Builder::default() - .push_data(&[0x00, 0x11, 0x22]) - .push_num(0.into()) - .push_opcode(Opcode::OP_SUBSTR) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_split(true), result, - vec![vec![0; 0].into(), vec![0x00, 0x11, 0x22].into()].into()); - } - - #[test] - fn op_split_non_empty_at_len_succeeds() { - // x len(x) OP_SPLIT -> x OP_0 - let script = Builder::default() - .push_data(&[0x00, 0x11, 0x22]) - .push_num(3.into()) - .push_opcode(Opcode::OP_SUBSTR) - .into_script(); - let result = Ok(false); - basic_test_with_flags(&script, &VerificationFlags::default().verify_split(true), result, - vec![vec![0x00, 0x11, 0x22].into(), vec![0; 0].into()].into()); - } - - #[test] - fn op_split_non_empty_at_post_len_fails() { - // x (len(x) + 1) OP_SPLIT -> FAIL - let script = Builder::default() - .push_data(&[0x00, 0x11, 0x22]) - .push_num(4.into()) - .push_opcode(Opcode::OP_SUBSTR) - .into_script(); - let result = Err(Error::InvalidSplitRange); - basic_test_with_flags(&script, &VerificationFlags::default().verify_split(true), result, - vec![].into()); - } - - #[test] - fn op_split_non_empty_at_mid_succeeds() { - let script = Builder::default() - .push_data(&[0x00, 0x11, 0x22]) - .push_num(2.into()) - .push_opcode(Opcode::OP_SUBSTR) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_split(true), result, - vec![vec![0x00, 0x11].into(), vec![0x22].into()].into()); - } - - #[test] - fn op_split_fails_if_position_is_nan() { - let script = Builder::default() - .push_data(&[0x00, 0x11, 0x22]) - .push_opcode(Opcode::OP_1NEGATE) // NaN - .push_opcode(Opcode::OP_SUBSTR) - .into_script(); - let result = Err(Error::InvalidStackOperation); - basic_test_with_flags(&script, &VerificationFlags::default().verify_split(true), result, - vec![].into()); - } - - #[test] - fn op_split_fails_if_position_is_negative() { - let script = Builder::default() - .push_data(&[0x00, 0x11, 0x22]) - .push_num((-10).into()) - .push_opcode(Opcode::OP_SUBSTR) - .into_script(); - let result = Err(Error::InvalidStackOperation); - basic_test_with_flags(&script, &VerificationFlags::default().verify_split(true), result, - vec![].into()); - } - - #[test] - fn op_and_disabled_by_default() { - let script = Builder::default() - .push_data(&[0x11]) - .push_data(&[0x22]) - .push_opcode(Opcode::OP_AND) - .into_script(); - let result = Err(Error::DisabledOpcode(Opcode::OP_AND)); - basic_test_with_flags(&script, &VerificationFlags::default(), result, - vec![].into()); - } - - #[test] - fn op_and_fails_with_different_len_args() { - let script = Builder::default() - .push_data(&[0x11, 0x22]) - .push_data(&[0x22]) - .push_opcode(Opcode::OP_AND) - .into_script(); - let result = Err(Error::InvalidOperandSize); - basic_test_with_flags(&script, &VerificationFlags::default().verify_and(true), result, - vec![].into()); - } - - #[test] - fn op_and_succeeds() { - let script = Builder::default() - .push_data(&[0x34, 0x56]) - .push_data(&[0x56, 0x78]) - .push_opcode(Opcode::OP_AND) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_and(true), result, - vec![vec![0x14, 0x50].into()].into()); - } - - #[test] - fn op_or_disabled_by_default() { - let script = Builder::default() - .push_data(&[0x11]) - .push_data(&[0x22]) - .push_opcode(Opcode::OP_OR) - .into_script(); - let result = Err(Error::DisabledOpcode(Opcode::OP_OR)); - basic_test_with_flags(&script, &VerificationFlags::default(), result, - vec![].into()); - } - - #[test] - fn op_or_fails_with_different_len_args() { - let script = Builder::default() - .push_data(&[0x11, 0x22]) - .push_data(&[0x22]) - .push_opcode(Opcode::OP_OR) - .into_script(); - let result = Err(Error::InvalidOperandSize); - basic_test_with_flags(&script, &VerificationFlags::default().verify_or(true), result, - vec![].into()); - } - - #[test] - fn op_or_succeeds() { - let script = Builder::default() - .push_data(&[0x34, 0x56]) - .push_data(&[0x56, 0x78]) - .push_opcode(Opcode::OP_OR) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_or(true), result, - vec![vec![0x76, 0x7e].into()].into()); - } - - #[test] - fn op_xor_disabled_by_default() { - let script = Builder::default() - .push_data(&[0x11]) - .push_data(&[0x22]) - .push_opcode(Opcode::OP_XOR) - .into_script(); - let result = Err(Error::DisabledOpcode(Opcode::OP_XOR)); - basic_test_with_flags(&script, &VerificationFlags::default(), result, - vec![].into()); - } - - #[test] - fn op_xor_fails_with_different_len_args() { - let script = Builder::default() - .push_data(&[0x11, 0x22]) - .push_data(&[0x22]) - .push_opcode(Opcode::OP_XOR) - .into_script(); - let result = Err(Error::InvalidOperandSize); - basic_test_with_flags(&script, &VerificationFlags::default().verify_xor(true), result, - vec![].into()); - } - - #[test] - fn op_xor_succeeds() { - let script = Builder::default() - .push_data(&[0x34, 0x56]) - .push_data(&[0x56, 0x78]) - .push_opcode(Opcode::OP_XOR) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_xor(true), result, - vec![vec![0x62, 0x2e].into()].into()); - } - - #[test] - fn op_div_disabled_by_default() { - let script = Builder::default() - .push_num(13.into()) - .push_num(5.into()) - .push_opcode(Opcode::OP_DIV) - .into_script(); - let result = Err(Error::DisabledOpcode(Opcode::OP_DIV)); - basic_test_with_flags(&script, &VerificationFlags::default(), result, - vec![].into()); - } - - #[test] - fn op_div_num_by_nan_fails() { - // a b OP_DIV -> failure where !isnum(a) or !isnum(b). Both operands must be valid numbers - let script = Builder::default() - .push_opcode(Opcode::OP_1SUB) - .push_num(5.into()) - .push_opcode(Opcode::OP_DIV) - .into_script(); - let result = Err(Error::InvalidStackOperation); - basic_test_with_flags(&script, &VerificationFlags::default().verify_div(true), result, - vec![].into()); - } - - #[test] - fn op_div_nan_by_num_fails() { - // a b OP_DIV -> failure where !isnum(a) or !isnum(b). Both operands must be valid numbers - let script = Builder::default() - .push_num(5.into()) - .push_opcode(Opcode::OP_1SUB) - .push_opcode(Opcode::OP_DIV) - .into_script(); - let result = Err(Error::InvalidStackOperation); - basic_test_with_flags(&script, &VerificationFlags::default().verify_div(true), result, - vec![].into()); - } - - #[test] - fn op_div_num_by_zero_fails() { - // a 0 OP_DIV -> failure. Division by positive zero (all sizes), negative zero (all sizes), OP_0 - let script = Builder::default() - .push_num(0.into()) - .push_num(5.into()) - .push_opcode(Opcode::OP_DIV) - .into_script(); - let result = Err(Error::DivisionByZero); - basic_test_with_flags(&script, &VerificationFlags::default().verify_div(true), result, - vec![].into()); - } - - #[test] - fn op_div_negative_by_negative_succeeds() { - let script = Builder::default() - .push_num((-5).into()) - .push_num((-13).into()) - .push_opcode(Opcode::OP_DIV) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_div(true), result, - vec![Num::from(2).to_bytes()].into()); - } - - #[test] - fn op_div_negative_by_positive_succeeds() { - let script = Builder::default() - .push_num(5.into()) - .push_num((-13).into()) - .push_opcode(Opcode::OP_DIV) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_div(true), result, - vec![Num::from(-2).to_bytes()].into()); - } - - #[test] - fn op_div_positive_by_negative_succeeds() { - let script = Builder::default() - .push_num((-5).into()) - .push_num(13.into()) - .push_opcode(Opcode::OP_DIV) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_div(true), result, - vec![Num::from(-2).to_bytes()].into()); - } - - #[test] - fn op_div_positive_by_positive_succeeds() { - let script = Builder::default() - .push_num(5.into()) - .push_num(13.into()) - .push_opcode(Opcode::OP_DIV) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_div(true), result, - vec![Num::from(2).to_bytes()].into()); - } - - #[test] - fn op_mod_disabled_by_default() { - let script = Builder::default() - .push_num(13.into()) - .push_num(5.into()) - .push_opcode(Opcode::OP_MOD) - .into_script(); - let result = Err(Error::DisabledOpcode(Opcode::OP_MOD)); - basic_test_with_flags(&script, &VerificationFlags::default(), result, - vec![].into()); - } - - #[test] - fn op_mod_num_by_nan_fails() { - // a b OP_MOD -> failure where !isnum(a) or !isnum(b). Both operands must be valid numbers - let script = Builder::default() - .push_opcode(Opcode::OP_1SUB) - .push_num(5.into()) - .push_opcode(Opcode::OP_MOD) - .into_script(); - let result = Err(Error::InvalidStackOperation); - basic_test_with_flags(&script, &VerificationFlags::default().verify_mod(true), result, - vec![].into()); - } - - #[test] - fn op_mod_nan_by_num_fails() { - // a b OP_MOD -> failure where !isnum(a) or !isnum(b). Both operands must be valid numbers - let script = Builder::default() - .push_num(5.into()) - .push_opcode(Opcode::OP_1SUB) - .push_opcode(Opcode::OP_MOD) - .into_script(); - let result = Err(Error::InvalidStackOperation); - basic_test_with_flags(&script, &VerificationFlags::default().verify_mod(true), result, - vec![].into()); - } - - #[test] - fn op_mod_num_by_zero_fails() { - // a 0 OP_MOD -> failure. Division by positive zero (all sizes), negative zero (all sizes), OP_0 - let script = Builder::default() - .push_num(0.into()) - .push_num(5.into()) - .push_opcode(Opcode::OP_MOD) - .into_script(); - let result = Err(Error::DivisionByZero); - basic_test_with_flags(&script, &VerificationFlags::default().verify_mod(true), result, - vec![].into()); - } - - #[test] - fn op_mod_negative_by_negative_succeeds() { - let script = Builder::default() - .push_num((-5).into()) - .push_num((-13).into()) - .push_opcode(Opcode::OP_MOD) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_mod(true), result, - vec![Num::from(-3).to_bytes()].into()); - } - - #[test] - fn op_mod_negative_by_positive_succeeds() { - let script = Builder::default() - .push_num(5.into()) - .push_num((-13).into()) - .push_opcode(Opcode::OP_MOD) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_mod(true), result, - vec![Num::from(-3).to_bytes()].into()); - } - - #[test] - fn op_mod_positive_by_negative_succeeds() { - let script = Builder::default() - .push_num((-5).into()) - .push_num(13.into()) - .push_opcode(Opcode::OP_MOD) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_mod(true), result, - vec![Num::from(3).to_bytes()].into()); - } - - #[test] - fn op_mod_positive_by_positive_succeeds() { - let script = Builder::default() - .push_num(5.into()) - .push_num(13.into()) - .push_opcode(Opcode::OP_MOD) - .into_script(); - let result = Ok(true); - basic_test_with_flags(&script, &VerificationFlags::default().verify_mod(true), result, - vec![Num::from(3).to_bytes()].into()); - } - - #[test] - fn op_bin2num_disabled_by_default() { - let script = Builder::default() - .push_num(0.into()) - .push_opcode(Opcode::OP_RIGHT) - .into_script(); - let result = Err(Error::DisabledOpcode(Opcode::OP_RIGHT)); - basic_test_with_flags(&script, &VerificationFlags::default(), result, - vec![].into()); - } - - #[test] - fn test_bin2num_all() { - fn test_bin2num(input: &[u8], result: Result, output: Vec) { - let script = Builder::default() - .push_bytes(input) - .push_opcode(Opcode::OP_RIGHT) - .into_script(); - let stack = if result.is_ok() { - vec![output.into()].into() - } else { - vec![] - }.into(); - let flags = VerificationFlags::default() - .verify_bin2num(true); - basic_test_with_flags(&script, &flags, result, stack); - } - - test_bin2num(&[0x02, 0x00, 0x00, 0x00, 0x00], Ok(true), vec![0x02]); - test_bin2num(&[0x05, 0x00, 0x80], Ok(true), vec![0x85]); - test_bin2num(&[0x02, 0x02, 0x02, 0x02, 0x02], Err(Error::NumberOverflow), vec![]); - test_bin2num(&[0x00], Ok(false), vec![]); - test_bin2num(&[0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], Ok(true), vec![0x01]); - test_bin2num(&[0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80], Ok(true), vec![0x81]); - test_bin2num(&[0x80], Ok(false), vec![]); - test_bin2num(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80], Ok(false), vec![]); - } - - #[test] - fn op_num2bin_disabled_by_default() { - let script = Builder::default() - .push_num(1.into()) - .push_num(1.into()) - .push_opcode(Opcode::OP_LEFT) - .into_script(); - let result = Err(Error::DisabledOpcode(Opcode::OP_LEFT)); - basic_test_with_flags(&script, &VerificationFlags::default(), result, - vec![].into()); - } - - #[test] - fn test_num2bin_all() { - fn test_num2bin(num: &[u8], size: &[u8], result: Result, output: Vec) { - let script = Builder::default() - .push_data(num) - .push_data(size) - .push_opcode(Opcode::OP_LEFT) - .into_script(); - let stack = if result.is_ok() { - vec![output.into()].into() - } else { - vec![] - }.into(); - - let flags = VerificationFlags::default() - .verify_num2bin(true); - basic_test_with_flags(&script, &flags, result, stack); - } - - fn test_num2bin_num(num: Num, size: Num, result: Result, output: Vec) { - test_num2bin(&*num.to_bytes(), &*size.to_bytes(), result, output) - } - - test_num2bin_num(256.into(), 1.into(), Err(Error::ImpossibleEncoding), vec![0x00]); - test_num2bin_num(1.into(), (MAX_SCRIPT_ELEMENT_SIZE + 1).into(), Err(Error::PushSize), vec![0x00]); - - test_num2bin_num(0.into(), 0.into(), Ok(false), vec![]); - test_num2bin_num(0.into(), 1.into(), Ok(false), vec![0x00]); - test_num2bin_num(0.into(), 7.into(), Ok(false), vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); - test_num2bin_num(1.into(), 1.into(), Ok(true), vec![0x01]); - test_num2bin_num((-42).into(), 1.into(), Ok(true), Num::from(-42).to_bytes().to_vec()); - test_num2bin_num((-42).into(), 2.into(), Ok(true), vec![0x2a, 0x80]); - test_num2bin_num((-42).into(), 10.into(), Ok(true), vec![0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]); - test_num2bin_num((-42).into(), 520.into(), Ok(true), ::std::iter::once(0x2a) - .chain(::std::iter::repeat(0x00).take(518)) - .chain(::std::iter::once(0x80)).collect()); - test_num2bin_num((-42).into(), 521.into(), Err(Error::PushSize), vec![]); - test_num2bin_num((-42).into(), (-3).into(), Err(Error::PushSize), vec![]); - - test_num2bin(&vec![0xab, 0xcd, 0xef, 0x42, 0x80], &vec![0x04], Ok(true), vec![0xab, 0xcd, 0xef, 0xc2]); - test_num2bin(&vec![0x80], &vec![0x00], Ok(false), vec![]); - test_num2bin(&vec![0x80], &vec![0x03], Ok(false), vec![0x00, 0x00, 0x00]); - } - - #[test] - fn test_num_bin_conversions_are_reverse_ops() { - let script = Builder::default() - // convert num2bin - .push_num(123456789.into()) - .push_num(8.into()) - .push_opcode(Opcode::OP_LEFT) - // and then back bin2num - .push_opcode(Opcode::OP_RIGHT) - // check that numbers are the same - .push_num(123456789.into()) - .push_opcode(Opcode::OP_EQUAL) - .into_script(); - - let flags = VerificationFlags::default() - .verify_num2bin(true) - .verify_bin2num(true); - basic_test_with_flags(&script, &flags, Ok(true), vec![vec![0x01].into()].into()); - } - - #[test] - fn test_split_cat_are_reverse_ops() { - let script = Builder::default() - // split array - .push_data(&vec![0x01, 0x02, 0x03, 0x04, 0x05]) - .push_num(2.into()) - .push_opcode(Opcode::OP_SUBSTR) - // and then concat again - .push_opcode(Opcode::OP_CAT) - // check that numbers are the same - .push_data(&vec![0x01, 0x02, 0x03, 0x04, 0x05]) - .push_opcode(Opcode::OP_EQUAL) - .into_script(); - - let flags = VerificationFlags::default() - .verify_concat(true) - .verify_split(true); - basic_test_with_flags(&script, &flags, Ok(true), vec![vec![0x01].into()].into()); - } - - #[test] - fn checkdatasig_spec_tests() { - // official tests from: - // https://github.com/bitcoincashorg/bitcoincash.org/blob/0c6f91b0b713aae3bc6c9834b46e80e247ff5fab/spec/op_checkdatasig.md - - let kp = KeyPair::from_private(Private { network: Network::Mainnet, secret: 1.into(), compressed: false, }).unwrap(); - - let pubkey = kp.public().clone(); - let message = vec![42u8; 32]; - let correct_signature = kp.private().sign(&Message::from(sha256(&message))).unwrap(); - let correct_signature_for_other_message = kp.private().sign(&[43u8; 32].into()).unwrap(); - let mut correct_signature = correct_signature.to_vec(); - let mut correct_signature_for_other_message = correct_signature_for_other_message.to_vec(); - correct_signature.push(0x81); - correct_signature_for_other_message.push(0x81); - - let correct_flags = VerificationFlags::default() - .verify_checkdatasig(true) - .verify_dersig(true) - .verify_strictenc(true); - let incorrect_flags = VerificationFlags::default().verify_checkdatasig(false); - - let correct_signature_script = Builder::default() - .push_data(&*correct_signature) - .push_data(&*message) - .push_data(&*pubkey) - .push_opcode(Opcode::OP_CHECKDATASIG) - .into_script(); - - // OP_CHECKDATASIG fails if 15 November 2018 protocol upgrade is not yet activated. - basic_test_with_flags(&correct_signature_script, &incorrect_flags, Err(Error::DisabledOpcode(Opcode::OP_CHECKDATASIG)), vec![].into()); - - // OP_CHECKDATASIG fails if there are fewer than 3 items on stack. - let too_few_args_sig_script = Builder::default() - .push_data(&[1u8; 32]) - .push_data(&*message) - .push_opcode(Opcode::OP_CHECKDATASIG) - .into_script(); - basic_test_with_flags(&too_few_args_sig_script, &correct_flags, Err(Error::InvalidStackOperation), vec![].into()); - - // OP_CHECKDATASIG fails if is not a validly encoded public key. - let incorrect_pubkey_script = Builder::default() - .push_data(&*correct_signature) - .push_data(&*message) - .push_data(&[77u8; 15]) - .push_opcode(Opcode::OP_CHECKDATASIG) - .into_script(); - basic_test_with_flags(&incorrect_pubkey_script, &correct_flags, Err(Error::PubkeyType), vec![].into()); - - // assuming that check_signature_encoding correctness is proved by other tests: - // OP_CHECKDATASIG fails if is not a validly encoded signature with strict DER encoding. - // OP_CHECKDATASIG fails if signature is not empty and does not pass the Low S check. - let incorrectly_encoded_signature_script = Builder::default() - .push_data(&[0u8; 65]) - .push_data(&*message) - .push_data(&*pubkey) - .push_opcode(Opcode::OP_CHECKDATASIG) - .into_script(); - basic_test_with_flags(&incorrectly_encoded_signature_script, &correct_flags, Err(Error::SignatureDer), vec![].into()); - - // OP_CHECKDATASIG fails if signature is not empty and does not pass signature validation of and . - let incorrect_signature_script = Builder::default() - .push_data(&*correct_signature_for_other_message) - .push_data(&*message) - .push_data(&*pubkey) - .push_opcode(Opcode::OP_CHECKDATASIG) - .into_script(); - basic_test_with_flags(&incorrect_signature_script, &correct_flags, Ok(false), vec![vec![0].into()].into()); - - // OP_CHECKDATASIG pops three elements and pushes false onto the stack if is an empty byte array. - let empty_signature_script = Builder::default() - .push_data(&[]) - .push_data(&*message) - .push_data(&*pubkey) - .push_opcode(Opcode::OP_CHECKDATASIG) - .into_script(); - basic_test_with_flags(&empty_signature_script, &correct_flags, Ok(false), vec![vec![0].into()].into()); - - // OP_CHECKDATASIG pops three elements and pushes true onto the stack if is a valid signature of with respect to . - basic_test_with_flags(&correct_signature_script, &correct_flags, Ok(true), vec![vec![1].into()].into()); - } - - #[test] - fn checkdatasigverify_spec_tests() { - // official tests from: - // https://github.com/bitcoincashorg/bitcoincash.org/blob/0c6f91b0b713aae3bc6c9834b46e80e247ff5fab/spec/op_checkdatasig.md - - let kp = KeyPair::from_private(Private { network: Network::Mainnet, secret: 1.into(), compressed: false, }).unwrap(); - - let pubkey = kp.public().clone(); - let message = vec![42u8; 32]; - let correct_signature = kp.private().sign(&Message::from(sha256(&message))).unwrap(); - let correct_signature_for_other_message = kp.private().sign(&[43u8; 32].into()).unwrap(); - let mut correct_signature = correct_signature.to_vec(); - let mut correct_signature_for_other_message = correct_signature_for_other_message.to_vec(); - correct_signature.push(0x81); - correct_signature_for_other_message.push(0x81); - - let correct_flags = VerificationFlags::default() - .verify_checkdatasig(true) - .verify_dersig(true) - .verify_strictenc(true); - let incorrect_flags = VerificationFlags::default().verify_checkdatasig(false); - - let correct_signature_script = Builder::default() - .push_data(&*correct_signature) - .push_data(&*message) - .push_data(&*pubkey) - .push_opcode(Opcode::OP_CHECKDATASIGVERIFY) - .into_script(); - - // OP_CHECKDATASIGVERIFY fails if 15 November 2018 protocol upgrade is not yet activated. - basic_test_with_flags(&correct_signature_script, &incorrect_flags, Err(Error::DisabledOpcode(Opcode::OP_CHECKDATASIGVERIFY)), vec![].into()); - - // OP_CHECKDATASIGVERIFY fails if there are fewer than 3 item on stack. - let too_few_args_sig_script = Builder::default() - .push_data(&[1u8; 32]) - .push_data(&*message) - .push_opcode(Opcode::OP_CHECKDATASIGVERIFY) - .into_script(); - basic_test_with_flags(&too_few_args_sig_script, &correct_flags, Err(Error::InvalidStackOperation), vec![].into()); - - // OP_CHECKDATASIGVERIFYfails if is not a validly encoded public key. - let incorrect_pubkey_script = Builder::default() - .push_data(&*correct_signature) - .push_data(&*message) - .push_data(&[77u8; 15]) - .push_opcode(Opcode::OP_CHECKDATASIGVERIFY) - .into_script(); - basic_test_with_flags(&incorrect_pubkey_script, &correct_flags, Err(Error::PubkeyType), vec![].into()); - - // assuming that check_signature_encoding correctness is proved by other tests: - // OP_CHECKDATASIGVERIFY fails if is not a validly encoded signature with strict DER encoding. - // OP_CHECKDATASIGVERIFY fails if signature is not empty and does not pass the Low S check. - let incorrectly_encoded_signature_script = Builder::default() - .push_data(&[0u8; 65]) - .push_data(&*message) - .push_data(&*pubkey) - .push_opcode(Opcode::OP_CHECKDATASIGVERIFY) - .into_script(); - basic_test_with_flags(&incorrectly_encoded_signature_script, &correct_flags, Err(Error::SignatureDer), vec![].into()); - - // OP_CHECKDATASIGVERIFY fails if is not a valid signature of with respect to . - let incorrect_signature_script = Builder::default() - .push_data(&*correct_signature_for_other_message) - .push_data(&*message) - .push_data(&*pubkey) - .push_opcode(Opcode::OP_CHECKDATASIGVERIFY) - .into_script(); - basic_test_with_flags(&incorrect_signature_script, &correct_flags, Err(Error::CheckDataSigVerify), vec![].into()); - - // OP_CHECKDATASIGVERIFY pops the top three stack elements if is a valid signature of with respect to . - // Ok(false) means success here, because OP_CHECKDATASIGVERIFY leaves empty stack - basic_test_with_flags(&correct_signature_script, &correct_flags, Ok(false), vec![].into()); - } } diff --git a/script/src/opcode.rs b/script/src/opcode.rs index 0538a1db..d607ca53 100644 --- a/script/src/opcode.rs +++ b/script/src/opcode.rs @@ -1,6 +1,5 @@ //! Script opcodes. use std::fmt; -use flags::VerificationFlags; /// Script opcodes. #[repr(u8)] @@ -213,10 +212,6 @@ pub enum Opcode { OP_NOP8 = 0xb7, OP_NOP9 = 0xb8, OP_NOP10 = 0xb9, - - // BCH crypto - OP_CHECKDATASIG = 0xba, - OP_CHECKDATASIGVERIFY = 0xbb, } impl fmt::Display for Opcode { @@ -434,27 +429,15 @@ impl Opcode { 0xb8 => Some(OP_NOP9), 0xb9 => Some(OP_NOP10), - // BCH crypto - 0xba => Some(OP_CHECKDATASIG), - 0xbb => Some(OP_CHECKDATASIGVERIFY), - _ => None, } } - pub fn is_disabled(&self, flags: &VerificationFlags) -> bool { + pub fn is_disabled(&self) -> bool { use self::Opcode::*; match *self { - OP_CAT if !flags.verify_concat => true, - OP_SUBSTR if !flags.verify_split => true, - OP_AND if !flags.verify_and => true, - OP_OR if !flags.verify_or => true, - OP_XOR if !flags.verify_xor => true, - OP_DIV if !flags.verify_div => true, - OP_MOD if !flags.verify_mod => true, - OP_RIGHT if !flags.verify_bin2num => true, - OP_LEFT if !flags.verify_num2bin => true, - OP_INVERT | OP_2MUL | OP_2DIV | + OP_CAT | OP_SUBSTR | OP_AND | OP_OR | OP_XOR | OP_DIV | + OP_MOD | OP_RIGHT | OP_LEFT | OP_INVERT | OP_2MUL | OP_2DIV | OP_MUL | OP_LSHIFT | OP_RSHIFT => true, _ => false, } @@ -695,9 +678,5 @@ mod tests { assert_eq!(Opcode::OP_NOP8, Opcode::from_u8(Opcode::OP_NOP8 as u8).unwrap()); assert_eq!(Opcode::OP_NOP9, Opcode::from_u8(Opcode::OP_NOP9 as u8).unwrap()); assert_eq!(Opcode::OP_NOP10, Opcode::from_u8(Opcode::OP_NOP10 as u8).unwrap()); - - // BCH crypto - assert_eq!(Opcode::OP_CHECKDATASIG, Opcode::from_u8(Opcode::OP_CHECKDATASIG as u8).unwrap()); - assert_eq!(Opcode::OP_CHECKDATASIGVERIFY, Opcode::from_u8(Opcode::OP_CHECKDATASIGVERIFY as u8).unwrap()); } } diff --git a/script/src/script.rs b/script/src/script.rs index 0d287693..2f9cfddd 100644 --- a/script/src/script.rs +++ b/script/src/script.rs @@ -286,7 +286,7 @@ impl Script { Opcodes { position: 0, script: self } } - pub fn sigops_count(&self, checkdatasig_active: bool, serialized_script: bool) -> usize { + pub fn sigops_count(&self, serialized_script: bool) -> usize { let mut last_opcode = Opcode::OP_0; let mut total = 0; for opcode in self.opcodes() { @@ -300,9 +300,6 @@ impl Script { Opcode::OP_CHECKSIG | Opcode::OP_CHECKSIGVERIFY => { total += 1; }, - Opcode::OP_CHECKDATASIG | Opcode::OP_CHECKDATASIGVERIFY if checkdatasig_active => { - total += 1; - }, Opcode::OP_CHECKMULTISIG | Opcode::OP_CHECKMULTISIGVERIFY => { if serialized_script && last_opcode.is_within_op_n() { total += last_opcode.decode_op_n() as usize; @@ -370,7 +367,7 @@ impl Script { } } - pub fn pay_to_script_hash_sigops(&self, checkdatasig_active: bool, prev_out: &Script) -> usize { + pub fn pay_to_script_hash_sigops(&self, prev_out: &Script) -> usize { if !prev_out.is_pay_to_script_hash() { return 0; } @@ -386,7 +383,7 @@ impl Script { .to_vec() .into(); - script.sigops_count(checkdatasig_active, true) + script.sigops_count(true) } } @@ -550,11 +547,11 @@ OP_ADD #[test] fn test_sigops_count() { - assert_eq!(1usize, Script::from("76a914aab76ba4877d696590d94ea3e02948b55294815188ac").sigops_count(false, false)); - assert_eq!(2usize, Script::from("522102004525da5546e7603eefad5ef971e82f7dad2272b34e6b3036ab1fe3d299c22f21037d7f2227e6c646707d1c61ecceb821794124363a2cf2c1d2a6f28cf01e5d6abe52ae").sigops_count(false, true)); - assert_eq!(20usize, Script::from("522102004525da5546e7603eefad5ef971e82f7dad2272b34e6b3036ab1fe3d299c22f21037d7f2227e6c646707d1c61ecceb821794124363a2cf2c1d2a6f28cf01e5d6abe52ae").sigops_count(false, false)); - assert_eq!(0usize, Script::from("a9146262b64aec1f4a4c1d21b32e9c2811dd2171fd7587").sigops_count(false, false)); - assert_eq!(1usize, Script::from("4104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac").sigops_count(false, false)); + assert_eq!(1usize, Script::from("76a914aab76ba4877d696590d94ea3e02948b55294815188ac").sigops_count(false)); + assert_eq!(2usize, Script::from("522102004525da5546e7603eefad5ef971e82f7dad2272b34e6b3036ab1fe3d299c22f21037d7f2227e6c646707d1c61ecceb821794124363a2cf2c1d2a6f28cf01e5d6abe52ae").sigops_count(true)); + assert_eq!(20usize, Script::from("522102004525da5546e7603eefad5ef971e82f7dad2272b34e6b3036ab1fe3d299c22f21037d7f2227e6c646707d1c61ecceb821794124363a2cf2c1d2a6f28cf01e5d6abe52ae").sigops_count(false)); + assert_eq!(0usize, Script::from("a9146262b64aec1f4a4c1d21b32e9c2811dd2171fd7587").sigops_count(false)); + assert_eq!(1usize, Script::from("4104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac").sigops_count(false)); } #[test] @@ -569,7 +566,7 @@ OP_ADD script[max_block_sigops - block_sigops + 3] = (overmax >> 16) as u8; script[max_block_sigops - block_sigops + 4] = (overmax >> 24) as u8; let script: Script = script.into(); - assert_eq!(script.sigops_count(false, false), 20001); + assert_eq!(script.sigops_count(false), 20001); } #[test] @@ -583,7 +580,7 @@ OP_ADD script[max_block_sigops - block_sigops + 4] = 0xff; script[max_block_sigops - block_sigops + 5] = 0xff; let script: Script = script.into(); - assert_eq!(script.sigops_count(false, false), 20001); + assert_eq!(script.sigops_count(false), 20001); } @@ -677,14 +674,4 @@ OP_ADD assert_eq!(script.script_type(), ScriptType::ScriptHash); assert_eq!(script.num_signatures_required(), 1); } - - #[test] - fn test_num_signatures_with_checkdatasig() { - let script = Builder::default().push_opcode(Opcode::OP_CHECKDATASIG).into_script(); - assert_eq!(script.sigops_count(false, false), 0); - assert_eq!(script.sigops_count(true, false), 1); - let script = Builder::default().push_opcode(Opcode::OP_CHECKDATASIGVERIFY).into_script(); - assert_eq!(script.sigops_count(false, false), 0); - assert_eq!(script.sigops_count(true, false), 1); - } } diff --git a/storage/src/store.rs b/storage/src/store.rs index 68f70c49..af13fbd2 100644 --- a/storage/src/store.rs +++ b/storage/src/store.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use chain::BlockHeader; use { BestBlock, BlockProvider, BlockHeaderProvider, TransactionProvider, TransactionMetaProvider, - TransactionOutputProvider, BlockChain, IndexedBlockProvider, Forkable, Error, NullifierTracker, + TransactionOutputProvider, BlockChain, IndexedBlockProvider, Forkable, NullifierTracker, TreeStateProvider, }; diff --git a/verification/src/accept_block.rs b/verification/src/accept_block.rs index 74ebc802..9af99f2d 100644 --- a/verification/src/accept_block.rs +++ b/verification/src/accept_block.rs @@ -115,7 +115,6 @@ pub struct BlockSigops<'a> { block: CanonBlock<'a>, store: &'a TransactionOutputProvider, bip16_active: bool, - checkdatasig_active: bool, max_block_sigops: usize, } @@ -126,13 +125,11 @@ impl<'a> BlockSigops<'a> { consensus: &'a ConsensusParams, ) -> Self { let bip16_active = block.header.raw.time >= consensus.bip16_time; - let checkdatasig_active = false; BlockSigops { block: block, store: store, bip16_active, - checkdatasig_active, max_block_sigops: consensus.max_block_sigops(), } } @@ -140,7 +137,7 @@ impl<'a> BlockSigops<'a> { fn check(&self) -> Result<(), Error> { let store = DuplexTransactionOutputProvider::new(self.store, &*self.block); let sigops = self.block.transactions.iter() - .map(|tx| transaction_sigops(&tx.raw, &store, self.bip16_active, self.checkdatasig_active)) + .map(|tx| transaction_sigops(&tx.raw, &store, self.bip16_active)) .fold(0, |acc, tx_sigops| (acc + tx_sigops)); if sigops > self.max_block_sigops { diff --git a/verification/src/accept_transaction.rs b/verification/src/accept_transaction.rs index 6fce7f99..ac274129 100644 --- a/verification/src/accept_transaction.rs +++ b/verification/src/accept_transaction.rs @@ -313,8 +313,7 @@ impl<'a> TransactionSigops<'a> { fn check(&self) -> Result<(), TransactionError> { let bip16_active = self.time >= self.consensus_params.bip16_time; - let checkdatasig_active = false; - let sigops = transaction_sigops(&self.transaction.raw, &self.store, bip16_active, checkdatasig_active); + let sigops = transaction_sigops(&self.transaction.raw, &self.store, bip16_active); if sigops > self.max_sigops { Err(TransactionError::MaxSigops) } else { @@ -333,8 +332,6 @@ pub struct TransactionEval<'a> { verify_checksequence: bool, verify_dersig: bool, verify_nulldummy: bool, - verify_monolith_opcodes: bool, - verify_magnetic_anomaly_opcodes: bool, verify_sigpushonly: bool, verify_cleanstack: bool, consensus_branch_id: u32, @@ -354,12 +351,10 @@ impl<'a> TransactionEval<'a> { let verify_strictenc = false; let verify_locktime = height >= params.bip65_height; let verify_dersig = height >= params.bip66_height; - let verify_monolith_opcodes = false; - let verify_magnetic_anomaly_opcodes = false; let verify_checksequence = deployments.csv(); - let verify_sigpushonly = verify_magnetic_anomaly_opcodes; - let verify_cleanstack = verify_magnetic_anomaly_opcodes; + let verify_sigpushonly = false; + let verify_cleanstack = false; let consensus_branch_id = params.consensus_branch_id(height); @@ -373,8 +368,6 @@ impl<'a> TransactionEval<'a> { verify_checksequence: verify_checksequence, verify_dersig: verify_dersig, verify_nulldummy: false, - verify_monolith_opcodes: verify_monolith_opcodes, - verify_magnetic_anomaly_opcodes: verify_magnetic_anomaly_opcodes, verify_sigpushonly: verify_sigpushonly, verify_cleanstack: verify_cleanstack, consensus_branch_id: consensus_branch_id, @@ -435,16 +428,6 @@ impl<'a> TransactionEval<'a> { .verify_checksequence(self.verify_checksequence) .verify_dersig(self.verify_dersig) .verify_nulldummy(self.verify_nulldummy) - .verify_concat(self.verify_monolith_opcodes) - .verify_split(self.verify_monolith_opcodes) - .verify_and(self.verify_monolith_opcodes) - .verify_or(self.verify_monolith_opcodes) - .verify_xor(self.verify_monolith_opcodes) - .verify_div(self.verify_monolith_opcodes) - .verify_mod(self.verify_monolith_opcodes) - .verify_bin2num(self.verify_monolith_opcodes) - .verify_num2bin(self.verify_monolith_opcodes) - .verify_checkdatasig(self.verify_magnetic_anomaly_opcodes) .verify_sigpushonly(self.verify_sigpushonly) .verify_cleanstack(self.verify_cleanstack); diff --git a/verification/src/sigops.rs b/verification/src/sigops.rs index 7eb62842..945d0278 100644 --- a/verification/src/sigops.rs +++ b/verification/src/sigops.rs @@ -10,11 +10,10 @@ pub fn transaction_sigops( transaction: &Transaction, store: &TransactionOutputProvider, bip16_active: bool, - checkdatasig_active: bool, ) -> usize { let output_sigops: usize = transaction.outputs.iter().map(|output| { let output_script: Script = output.script_pubkey.clone().into(); - output_script.sigops_count(checkdatasig_active, false) + output_script.sigops_count(false) }).sum(); // TODO: bitcoin/bitcoin also includes input_sigops here @@ -27,14 +26,14 @@ pub fn transaction_sigops( for input in &transaction.inputs { let input_script: Script = input.script_sig.clone().into(); - input_sigops += input_script.sigops_count(checkdatasig_active, false); + input_sigops += input_script.sigops_count(false); if bip16_active { let previous_output = match store.transaction_output(&input.previous_output, usize::max_value()) { Some(output) => output, None => continue, }; let prevout_script: Script = previous_output.script_pubkey.into(); - bip16_sigops += input_script.pay_to_script_hash_sigops(checkdatasig_active, &prevout_script); + bip16_sigops += input_script.pay_to_script_hash_sigops(&prevout_script); } } diff --git a/verification/src/verify_block.rs b/verification/src/verify_block.rs index 39ce5618..b8a8024d 100644 --- a/verification/src/verify_block.rs +++ b/verification/src/verify_block.rs @@ -163,7 +163,7 @@ impl<'a> BlockSigops<'a> { fn check(&self) -> Result<(), Error> { // We cannot know if bip16 is enabled at this point so we disable it. let sigops = self.block.transactions.iter() - .map(|tx| transaction_sigops(&tx.raw, &NoopStore, false, false)) + .map(|tx| transaction_sigops(&tx.raw, &NoopStore, false)) .sum::(); if sigops > self.max_sigops { diff --git a/verification/src/verify_transaction.rs b/verification/src/verify_transaction.rs index a23aeedf..b57283c4 100644 --- a/verification/src/verify_transaction.rs +++ b/verification/src/verify_transaction.rs @@ -261,7 +261,7 @@ impl<'a> TransactionSigops<'a> { } fn check(&self) -> Result<(), TransactionError> { - let sigops = transaction_sigops(&self.transaction.raw, &NoopStore, false, false); + let sigops = transaction_sigops(&self.transaction.raw, &NoopStore, false); if sigops > self.max_sigops { Err(TransactionError::MaxSigops) } else { From aa497b71295b264bf29b65f7a7185d7dcd9bd88a Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Tue, 12 Mar 2019 13:37:30 +0300 Subject: [PATCH 6/6] rephrase --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 19830992..bc031c43 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ cargo test --all By default parity connects to Zcash seednodes. Full list is [here](./pzec/seednodes.rs). -To start syncing the main network, just start the client. For example: +To start syncing the main network, just start the client without any arguments: ``` ./target/release/pzec @@ -121,9 +121,9 @@ To not print any syncing progress add `--quiet` flag: ## Importing zcashd database - It it is possible to import existing `zcashd` database: +It it is possible to import existing `zcashd` database: - ``` +``` # where $ZCASH_DB is path to your zcashd database. By default: # on macOS: "/Users/user/Library/Application Support/Zcash" # on Linux: "~/.zcash"