diff --git a/data_structures/src/chain/mod.rs b/data_structures/src/chain/mod.rs index 472a6fbae..7cbffa281 100644 --- a/data_structures/src/chain/mod.rs +++ b/data_structures/src/chain/mod.rs @@ -40,7 +40,7 @@ use crate::{ }, get_environment, proto::{ - versioning::{ProtocolVersion, Versioned}, + versioning::{ProtocolVersion, Versioned, VersionedHashable}, ProtobufConvert, }, staking::prelude::*, @@ -756,13 +756,13 @@ pub struct BlockMerkleRoots { } /// Function to calculate a merkle tree from a transaction vector -pub fn merkle_tree_root(transactions: &[T]) -> Hash +pub fn merkle_tree_root(transactions: &[T], protocol_version: ProtocolVersion) -> Hash where - T: Hashable, + T: VersionedHashable, { let transactions_hashes: Vec = transactions .iter() - .map(|x| match x.hash() { + .map(|x| match x.versioned_hash(protocol_version) { Hash::SHA256(x) => Sha256(x), }) .collect(); @@ -773,16 +773,16 @@ where } impl BlockMerkleRoots { - pub fn from_transactions(txns: &BlockTransactions) -> Self { + pub fn from_transactions(txns: &BlockTransactions, protocol_version: ProtocolVersion) -> Self { BlockMerkleRoots { - mint_hash: txns.mint.hash(), - vt_hash_merkle_root: merkle_tree_root(&txns.value_transfer_txns), - dr_hash_merkle_root: merkle_tree_root(&txns.data_request_txns), - commit_hash_merkle_root: merkle_tree_root(&txns.commit_txns), - reveal_hash_merkle_root: merkle_tree_root(&txns.reveal_txns), - tally_hash_merkle_root: merkle_tree_root(&txns.tally_txns), - stake_hash_merkle_root: merkle_tree_root(&txns.stake_txns), - unstake_hash_merkle_root: merkle_tree_root(&txns.unstake_txns), + mint_hash: txns.mint.versioned_hash(protocol_version), + vt_hash_merkle_root: merkle_tree_root(&txns.value_transfer_txns, protocol_version), + dr_hash_merkle_root: merkle_tree_root(&txns.data_request_txns, protocol_version), + commit_hash_merkle_root: merkle_tree_root(&txns.commit_txns, protocol_version), + reveal_hash_merkle_root: merkle_tree_root(&txns.reveal_txns, protocol_version), + tally_hash_merkle_root: merkle_tree_root(&txns.tally_txns, protocol_version), + stake_hash_merkle_root: merkle_tree_root(&txns.stake_txns, protocol_version), + unstake_hash_merkle_root: merkle_tree_root(&txns.unstake_txns, protocol_version), } } } @@ -901,13 +901,13 @@ impl SuperBlock { &self, blocks: &[Block], tally_tx: &TallyTransaction, + protocol_version: ProtocolVersion, ) -> Option { // Get the PoI for the block root, if the tally transaction is found on the list of blocks // Obtain also the index of the tally root of the block containing the tally TX. - let (mut poi, tally_root_idx) = blocks - .iter() - .enumerate() - .find_map(|(idx, b)| Some((tally_tx.data_proof_of_inclusion(b)?, idx)))?; + let (mut poi, tally_root_idx) = blocks.iter().enumerate().find_map(|(idx, b)| { + Some((tally_tx.data_proof_of_inclusion(b, protocol_version)?, idx)) + })?; // Collect all tally roots from the blocks let tally_roots = blocks @@ -4726,10 +4726,11 @@ mod tests { expected_lemma_lengths: Vec, blocks: Vec, tally_txs: Vec, + protocol_version: ProtocolVersion, ) { for index in 0..expected_indices.len() { let result = sb - .tally_proof_of_inclusion(&blocks, &tally_txs[index]) + .tally_proof_of_inclusion(&blocks, &tally_txs[index], protocol_version) .unwrap(); assert_eq!(result.index, expected_indices[index]); assert_eq!(result.lemma.len(), expected_lemma_lengths[index]); @@ -6883,6 +6884,7 @@ mod tests { 1, Hash::default(), 1, + ProtocolVersion::default(), ); let expected_indices = vec![0, 2, 2]; @@ -6937,6 +6939,7 @@ mod tests { 1, Hash::default(), 1, + ProtocolVersion::default(), ); let expected_indices = vec![0, 2, 2, 8, 10, 6, 4, 6]; @@ -6972,6 +6975,7 @@ mod tests { 1, Hash::default(), 1, + ProtocolVersion::default(), ); let result = sb.dr_proof_of_inclusion(&[b1, b2], &dr_txs[2]); @@ -6982,7 +6986,14 @@ mod tests { fn test_dr_merkle_root_no_block() { let dr_txs = build_test_dr_txs(3); - let sb = mining_build_superblock(&[], &[Hash::default()], 1, Hash::default(), 1); + let sb = mining_build_superblock( + &[], + &[Hash::default()], + 1, + Hash::default(), + 1, + ProtocolVersion::default(), + ); let result = sb.dr_proof_of_inclusion(&[], &dr_txs[2]); assert!(result.is_none()); @@ -7008,6 +7019,7 @@ mod tests { 1, Hash::default(), 1, + ProtocolVersion::default(), ); let expected_indices = vec![0, 2]; @@ -7046,6 +7058,7 @@ mod tests { 1, Hash::default(), 1, + ProtocolVersion::default(), ); let expected_indices = vec![0, 2, 2]; @@ -7057,6 +7070,7 @@ mod tests { expected_lemma_lengths, vec![b1, b2], tally_txs, + ProtocolVersion::default(), ); } @@ -7108,6 +7122,7 @@ mod tests { 1, Hash::default(), 1, + ProtocolVersion::default(), ); let expected_indices = vec![0, 2, 2, 8, 10, 6, 4, 6]; @@ -7119,12 +7134,14 @@ mod tests { expected_lemma_lengths, vec![b1, b2, b3], tally_txs, + ProtocolVersion::default(), ); } #[test] fn test_tally_merkle_root_none() { let tally_txs = build_test_tally_txs(3); + let protocol_version = ProtocolVersion::default(); let mut b1 = block_example(); let mut b2 = block_example(); @@ -7143,9 +7160,10 @@ mod tests { 1, Hash::default(), 1, + ProtocolVersion::default(), ); - let result = sb.tally_proof_of_inclusion(&[b1, b2], &tally_txs[2]); + let result = sb.tally_proof_of_inclusion(&[b1, b2], &tally_txs[2], protocol_version); assert!(result.is_none()); } @@ -7174,6 +7192,7 @@ mod tests { 1, Hash::default(), 1, + ProtocolVersion::default(), ); let expected_indices = vec![0, 2, 2]; @@ -7185,6 +7204,7 @@ mod tests { expected_lemma_lengths, vec![b1], tally_txs, + ProtocolVersion::default(), ); } diff --git a/data_structures/src/lib.rs b/data_structures/src/lib.rs index 85418c898..91d03a5bf 100644 --- a/data_structures/src/lib.rs +++ b/data_structures/src/lib.rs @@ -17,10 +17,9 @@ use std::sync::RwLock; use lazy_static::lazy_static; -use crate::proto::versioning::ProtocolInfo; use crate::{ chain::{Environment, Epoch}, - proto::versioning::ProtocolVersion, + proto::versioning::{ProtocolInfo, ProtocolVersion}, }; pub const DEFAULT_VALIDATOR_COUNT_FOR_TESTS: usize = 1000; @@ -163,7 +162,7 @@ pub fn set_protocol_version(protocol_version: ProtocolVersion) { /// Refresh the protocol version, i.e. derive the current version from the current epoch, and update `current_version` /// accordingly. pub fn refresh_protocol_version(current_epoch: Epoch) { - let current_version = get_protocol_version(Some(current_epoch)); + let current_version = ProtocolVersion::from_epoch(current_epoch); set_protocol_version(current_version) } @@ -200,7 +199,7 @@ mod tests { // If this default changes before the transition to V2 is complete, almost everything will // break because data structures change schema and, serialization changes and hash // derivation breaks too - let protocol_version = get_protocol_version(None); + let protocol_version = ProtocolVersion::guess(); assert_eq!(protocol_version, ProtocolVersion::V1_7); // Register the different protocol versions @@ -209,23 +208,23 @@ mod tests { register_protocol_version(ProtocolVersion::V2_0, 300, 20); // The initial protocol version should be the default one - let version = get_protocol_version(Some(0)); + let version = ProtocolVersion::from_epoch(0); assert_eq!(version, ProtocolVersion::V1_7); // Right after the - let version = get_protocol_version(Some(100)); + let version = ProtocolVersion::from_epoch(100); assert_eq!(version, ProtocolVersion::V1_7); - let version = get_protocol_version(Some(200)); + let version = ProtocolVersion::from_epoch(200); assert_eq!(version, ProtocolVersion::V1_8); - let version = get_protocol_version(Some(300)); + let version = ProtocolVersion::from_epoch(300); assert_eq!(version, ProtocolVersion::V2_0); - let version = get_protocol_version(None); + let version = ProtocolVersion::guess(); assert_eq!(version, ProtocolVersion::V1_7); set_protocol_version(ProtocolVersion::V2_0); - let version = get_protocol_version(None); + let version = ProtocolVersion::guess(); assert_eq!(version, ProtocolVersion::V2_0); } } diff --git a/data_structures/src/proto/versioning.rs b/data_structures/src/proto/versioning.rs index 3cc34d128..fe720301c 100644 --- a/data_structures/src/proto/versioning.rs +++ b/data_structures/src/proto/versioning.rs @@ -91,6 +91,10 @@ impl ProtocolVersion { pub fn guess() -> Self { get_protocol_version(None) } + + pub fn from_epoch(epoch: Epoch) -> Self { + get_protocol_version(Some(epoch)) + } } impl PartialOrd for ProtocolVersion { diff --git a/data_structures/src/superblock.rs b/data_structures/src/superblock.rs index bfc08f9ca..63498aadc 100644 --- a/data_structures/src/superblock.rs +++ b/data_structures/src/superblock.rs @@ -424,6 +424,7 @@ impl SuperBlockState { sync_superblock: Option, block_epoch: Epoch, ) -> SuperBlock { + let protocol_version = ProtocolVersion::from_epoch(block_epoch); let key_leaves = hash_key_leaves(&ars_identities.get_rep_ordered_bn256_list(alt_keys)); self.update_ars_identities(ars_identities); @@ -474,6 +475,7 @@ impl SuperBlockState { superblock_index, last_block_in_previous_superblock, self.signing_committee.len() as u32, + protocol_version, ) }; @@ -679,6 +681,7 @@ pub fn mining_build_superblock( index: u32, last_block_in_previous_superblock: Hash, signing_committee_length: u32, + protocol_version: ProtocolVersion, ) -> SuperBlock { let last_block = block_headers.last(); match last_block { @@ -704,7 +707,7 @@ pub fn mining_build_superblock( ) } Some(last_block_header) => { - let last_block_hash = last_block_header.versioned_hash(ProtocolVersion::guess()); + let last_block_hash = last_block_header.versioned_hash(protocol_version); let merkle_drs: Vec = block_headers .iter() .map(|b| b.merkle_roots.dr_hash_merkle_root) @@ -717,7 +720,13 @@ pub fn mining_build_superblock( let ars_root = hash_merkle_tree_root(ars_ordered_hash_leaves); let blocks: Vec<_> = block_headers .iter() - .map(|b| format!("#{}: {}", b.beacon.checkpoint, b.hash())) + .map(|b| { + format!( + "#{}: {}", + b.beacon.checkpoint, + b.versioned_hash(protocol_version) + ) + }) .collect(); log::trace!( "Created superblock #{} with hash_prev_block {}, ARS {}, signing_committee_length: {}, blocks {:?}", @@ -775,7 +784,8 @@ mod tests { #[test] fn test_superblock_creation_no_blocks() { let default_hash = Hash::default(); - let superblock = mining_build_superblock(&[], &[], 0, default_hash, 0); + let superblock = + mining_build_superblock(&[], &[], 0, default_hash, 0, ProtocolVersion::default()); let expected = SuperBlock::new( 0, @@ -833,7 +843,14 @@ mod tests { tally_merkle_root_1, ); - let superblock = mining_build_superblock(&[block], &[default_hash], 0, default_hash, 1); + let superblock = mining_build_superblock( + &[block], + &[default_hash], + 0, + default_hash, + 1, + ProtocolVersion::default(), + ); assert_eq!(superblock, expected_superblock); } @@ -901,8 +918,14 @@ mod tests { expected_superblock_tally_root, ); - let superblock = - mining_build_superblock(&[block_1, block_2], &[default_hash], 0, default_hash, 1); + let superblock = mining_build_superblock( + &[block_1, block_2], + &[default_hash], + 0, + default_hash, + 1, + ProtocolVersion::default(), + ); assert_eq!(superblock, expected_superblock); } @@ -1917,6 +1940,7 @@ mod tests { 1, genesis_hash, 3, + ProtocolVersion::default(), ); let sb2_hash = expected_sb2.hash(); @@ -2018,6 +2042,7 @@ mod tests { 1, genesis_hash, 2, + ProtocolVersion::default(), ); assert_eq!(sb2, expected_sb2); @@ -2178,6 +2203,7 @@ mod tests { 1, genesis_hash, 2, + ProtocolVersion::default(), ); assert_eq!(sb2, expected_sb2); diff --git a/data_structures/src/transaction.rs b/data_structures/src/transaction.rs index 09c572658..4f8f2016e 100644 --- a/data_structures/src/transaction.rs +++ b/data_structures/src/transaction.rs @@ -15,7 +15,11 @@ use crate::{ PublicKeyHash, StakeOutput, ValueTransferOutput, }, error::TransactionError, - proto::{schema::witnet, ProtobufConvert}, + proto::{ + schema::witnet, + versioning::{ProtocolVersion, VersionedHashable}, + ProtobufConvert, + }, vrf::DataRequestEligibilityClaim, }; @@ -309,11 +313,17 @@ pub struct TxInclusionProof { impl TxInclusionProof { /// New inclusion proof given index and list of all the transactions in the /// block, in the same order. - pub fn new<'a, I: IntoIterator, H: 'a + Hashable>( + pub fn new<'a, I: IntoIterator, H: 'a + VersionedHashable>( index: usize, leaves: I, + protocol_version: ProtocolVersion, ) -> TxInclusionProof { - Self::new_with_hashes(index, leaves.into_iter().map(|t| t.hash())) + Self::new_with_hashes( + index, + leaves + .into_iter() + .map(|t| t.versioned_hash(protocol_version)), + ) } /// Create a TX inclusion proof assuming the inputs are already Hashes @@ -362,13 +372,17 @@ impl DRTransaction { /// Creates a proof of inclusion. /// /// Returns None if the transaction is not included in this block. - pub fn proof_of_inclusion(&self, block: &Block) -> Option { + pub fn proof_of_inclusion( + &self, + block: &Block, + protocol_version: ProtocolVersion, + ) -> Option { // Find the transaction in this block let txs = &block.txns.data_request_txns; txs.iter() .position(|x| x == self) - .map(|tx_idx| TxInclusionProof::new(tx_idx, txs)) + .map(|tx_idx| TxInclusionProof::new(tx_idx, txs, protocol_version)) } /// Returns the weight of a data request transaction. @@ -381,11 +395,12 @@ impl DRTransaction { /// Modify the proof of inclusion adding a new level that divide a specified data /// from the rest of transaction pub fn data_proof_of_inclusion(&self, block: &Block) -> Option { - self.proof_of_inclusion(block).map(|mut poi| { - poi.add_leave(self.body.rest_poi_hash()); + self.proof_of_inclusion(block, ProtocolVersion::default()) + .map(|mut poi| { + poi.add_leave(self.body.rest_poi_hash()); - poi - }) + poi + }) } } @@ -621,30 +636,39 @@ impl TallyTransaction { /// Rest of the transaction to be divided in a new level in the proof of inclusion /// In this case we choose the complete transaction - pub fn rest_poi_hash(&self) -> Hash { - calculate_sha256(&self.to_pb_bytes().unwrap()).into() + pub fn rest_poi_hash(&self, protocol_version: ProtocolVersion) -> Hash { + self.versioned_hash(protocol_version) } /// Creates a proof of inclusion. /// /// Returns None if the transaction is not included in this block. - pub fn proof_of_inclusion(&self, block: &Block) -> Option { + pub fn proof_of_inclusion( + &self, + block: &Block, + protocol_version: ProtocolVersion, + ) -> Option { // Find the transaction in this block let txs = &block.txns.tally_txns; txs.iter() .position(|x| x == self) - .map(|tx_idx| TxInclusionProof::new(tx_idx, txs)) + .map(|tx_idx| TxInclusionProof::new(tx_idx, txs, protocol_version)) } /// Modify the proof of inclusion adding a new level that divide a specified data /// from the rest of transaction - pub fn data_proof_of_inclusion(&self, block: &Block) -> Option { - self.proof_of_inclusion(block).map(|mut poi| { - poi.add_leave(self.rest_poi_hash()); - - poi - }) + pub fn data_proof_of_inclusion( + &self, + block: &Block, + protocol_version: ProtocolVersion, + ) -> Option { + self.proof_of_inclusion(block, protocol_version) + .map(|mut poi| { + poi.add_leave(self.rest_poi_hash(protocol_version)); + + poi + }) } } @@ -930,7 +954,7 @@ impl MemoizedHashable for UnstakeTransactionBody { impl MemoizedHashable for TallyTransaction { fn hashable_bytes(&self) -> Vec { let Hash::SHA256(data_bytes) = self.data_poi_hash(); - let Hash::SHA256(rest_bytes) = self.rest_poi_hash(); + let Hash::SHA256(rest_bytes) = self.rest_poi_hash(ProtocolVersion::default()); [data_bytes, rest_bytes].concat() } diff --git a/data_structures/tests/inclusion_proofs.rs b/data_structures/tests/inclusion_proofs.rs index e3f490d8e..aa09f7bf0 100644 --- a/data_structures/tests/inclusion_proofs.rs +++ b/data_structures/tests/inclusion_proofs.rs @@ -1,9 +1,10 @@ use std::convert::TryFrom; + use witnet_crypto::{ hash::Sha256, merkle::{sha256_concat, InclusionProof}, }; -use witnet_data_structures::{chain::*, transaction::*}; +use witnet_data_structures::{chain::*, proto::versioning::ProtocolVersion, transaction::*}; fn h(left: Hash, right: Hash) -> Hash { let left = match left { @@ -17,6 +18,7 @@ fn h(left: Hash, right: Hash) -> Hash { fn example_block(txns: BlockTransactions) -> Block { let current_epoch = 1000; + let protocol_version = ProtocolVersion::from_epoch(current_epoch); let last_block_hash = "62adde3e36db3f22774cc255215b2833575f66bf2204011f80c03d34c7c9ea41" .parse() .unwrap(); @@ -26,7 +28,7 @@ fn example_block(txns: BlockTransactions) -> Block { hash_prev_block: last_block_hash, }; let block_header = BlockHeader { - merkle_roots: BlockMerkleRoots::from_transactions(&txns), + merkle_roots: BlockMerkleRoots::from_transactions(&txns, protocol_version), beacon: block_beacon, ..Default::default() }; @@ -59,7 +61,10 @@ fn dr_inclusion_0_drs() { }); let dr = example_dr(0); - assert_eq!(dr.proof_of_inclusion(&block), None); + assert_eq!( + dr.proof_of_inclusion(&block, ProtocolVersion::default()), + None + ); } #[test] @@ -72,9 +77,12 @@ fn dr_inclusion_1_drs() { ..Default::default() }); - assert_eq!(drx.proof_of_inclusion(&block), None); assert_eq!( - dr0.proof_of_inclusion(&block), + drx.proof_of_inclusion(&block, ProtocolVersion::default()), + None + ); + assert_eq!( + dr0.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 0, lemma: vec![], @@ -93,16 +101,19 @@ fn dr_inclusion_2_drs() { ..Default::default() }); - assert_eq!(drx.proof_of_inclusion(&block), None); assert_eq!( - dr0.proof_of_inclusion(&block), + drx.proof_of_inclusion(&block, ProtocolVersion::default()), + None + ); + assert_eq!( + dr0.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 0, lemma: vec![dr1.hash()], }) ); assert_eq!( - dr1.proof_of_inclusion(&block), + dr1.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 1, lemma: vec![dr0.hash()], @@ -122,23 +133,26 @@ fn dr_inclusion_3_drs() { ..Default::default() }); - assert_eq!(drx.proof_of_inclusion(&block), None); assert_eq!( - dr0.proof_of_inclusion(&block), + drx.proof_of_inclusion(&block, ProtocolVersion::default()), + None + ); + assert_eq!( + dr0.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 0, lemma: vec![dr1.hash(), dr2.hash()], }) ); assert_eq!( - dr1.proof_of_inclusion(&block), + dr1.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 1, lemma: vec![dr0.hash(), dr2.hash()], }) ); assert_eq!( - dr2.proof_of_inclusion(&block), + dr2.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 1, lemma: vec![h(dr0.hash(), dr1.hash())], @@ -166,37 +180,40 @@ fn dr_inclusion_5_drs() { ..Default::default() }); - assert_eq!(drx.proof_of_inclusion(&block), None); assert_eq!( - dr0.proof_of_inclusion(&block), + drx.proof_of_inclusion(&block, ProtocolVersion::default()), + None + ); + assert_eq!( + dr0.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 0, lemma: vec![dr1.hash(), h(dr2.hash(), dr3.hash()), dr4.hash()], }) ); assert_eq!( - dr1.proof_of_inclusion(&block), + dr1.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 1, lemma: vec![dr0.hash(), h(dr2.hash(), dr3.hash()), dr4.hash()], }) ); assert_eq!( - dr2.proof_of_inclusion(&block), + dr2.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 2, lemma: vec![dr3.hash(), h(dr0.hash(), dr1.hash()), dr4.hash()], }) ); assert_eq!( - dr3.proof_of_inclusion(&block), + dr3.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 3, lemma: vec![dr2.hash(), h(dr0.hash(), dr1.hash()), dr4.hash()], }) ); assert_eq!( - dr4.proof_of_inclusion(&block), + dr4.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 1, lemma: vec![h(h(dr0.hash(), dr1.hash()), h(dr2.hash(), dr3.hash()))], @@ -212,7 +229,10 @@ fn ta_inclusion_0_tas() { }); let ta = example_ta(0); - assert_eq!(ta.proof_of_inclusion(&block), None); + assert_eq!( + ta.proof_of_inclusion(&block, ProtocolVersion::default()), + None + ); } #[test] @@ -225,9 +245,12 @@ fn ta_inclusion_1_tas() { ..Default::default() }); - assert_eq!(tax.proof_of_inclusion(&block), None); assert_eq!( - ta0.proof_of_inclusion(&block), + tax.proof_of_inclusion(&block, ProtocolVersion::default()), + None + ); + assert_eq!( + ta0.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 0, lemma: vec![], @@ -246,16 +269,19 @@ fn ta_inclusion_2_tas() { ..Default::default() }); - assert_eq!(tax.proof_of_inclusion(&block), None); assert_eq!( - ta0.proof_of_inclusion(&block), + tax.proof_of_inclusion(&block, ProtocolVersion::default()), + None + ); + assert_eq!( + ta0.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 0, lemma: vec![ta1.hash()], }) ); assert_eq!( - ta1.proof_of_inclusion(&block), + ta1.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 1, lemma: vec![ta0.hash()], @@ -275,23 +301,26 @@ fn ta_inclusion_3_tas() { ..Default::default() }); - assert_eq!(tax.proof_of_inclusion(&block), None); assert_eq!( - ta0.proof_of_inclusion(&block), + tax.proof_of_inclusion(&block, ProtocolVersion::default()), + None + ); + assert_eq!( + ta0.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 0, lemma: vec![ta1.hash(), ta2.hash()], }) ); assert_eq!( - ta1.proof_of_inclusion(&block), + ta1.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 1, lemma: vec![ta0.hash(), ta2.hash()], }) ); assert_eq!( - ta2.proof_of_inclusion(&block), + ta2.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 1, lemma: vec![h(ta0.hash(), ta1.hash())], @@ -319,37 +348,40 @@ fn ta_inclusion_5_tas() { ..Default::default() }); - assert_eq!(tax.proof_of_inclusion(&block), None); assert_eq!( - ta0.proof_of_inclusion(&block), + tax.proof_of_inclusion(&block, ProtocolVersion::default()), + None + ); + assert_eq!( + ta0.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 0, lemma: vec![ta1.hash(), h(ta2.hash(), ta3.hash()), ta4.hash()], }) ); assert_eq!( - ta1.proof_of_inclusion(&block), + ta1.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 1, lemma: vec![ta0.hash(), h(ta2.hash(), ta3.hash()), ta4.hash()], }) ); assert_eq!( - ta2.proof_of_inclusion(&block), + ta2.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 2, lemma: vec![ta3.hash(), h(ta0.hash(), ta1.hash()), ta4.hash()], }) ); assert_eq!( - ta3.proof_of_inclusion(&block), + ta3.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 3, lemma: vec![ta2.hash(), h(ta0.hash(), ta1.hash()), ta4.hash()], }) ); assert_eq!( - ta4.proof_of_inclusion(&block), + ta4.proof_of_inclusion(&block, ProtocolVersion::default()), Some(TxInclusionProof { index: 1, lemma: vec![h(h(ta0.hash(), ta1.hash()), h(ta2.hash(), ta3.hash()))], @@ -360,7 +392,9 @@ fn ta_inclusion_5_tas() { fn check_dr_data_proof_inclusion(dr: DRTransaction, block: &Block) { let mt_root = block.block_header.merkle_roots.dr_hash_merkle_root.into(); - let old_poi = dr.proof_of_inclusion(block).unwrap(); + let old_poi = dr + .proof_of_inclusion(block, ProtocolVersion::default()) + .unwrap(); let data_hash = dr.body.data_poi_hash(); let new_index = old_poi.index << 1; let mut new_lemma = old_poi.lemma; @@ -463,13 +497,16 @@ fn check_ta_data_proof_inclusion(ta: TallyTransaction, block: &Block) { .tally_hash_merkle_root .into(); - let old_poi = ta.proof_of_inclusion(block).unwrap(); + let old_poi = ta + .proof_of_inclusion(block, ProtocolVersion::default()) + .unwrap(); let data_hash = ta.data_poi_hash(); let new_index = old_poi.index << 1; + let protocol_version = ProtocolVersion::guess(); let mut new_lemma = old_poi.lemma; - new_lemma.insert(0, ta.rest_poi_hash()); + new_lemma.insert(0, ta.rest_poi_hash(protocol_version)); - let poi = ta.data_proof_of_inclusion(block); + let poi = ta.data_proof_of_inclusion(block, protocol_version); assert_eq!( poi, Some(TxInclusionProof { diff --git a/node/src/actors/chain_manager/handlers.rs b/node/src/actors/chain_manager/handlers.rs index db130c180..16ff82ed3 100644 --- a/node/src/actors/chain_manager/handlers.rs +++ b/node/src/actors/chain_manager/handlers.rs @@ -186,7 +186,8 @@ impl Handler> for ChainManager { "There was no valid block candidate to consolidate for epoch {}", previous_epoch ); - if get_protocol_version(Some(previous_epoch)) == ProtocolVersion::V2_0 { + if ProtocolVersion::from_epoch(previous_epoch) == ProtocolVersion::V2_0 + { let rank_subset: Vec<_> = stakes .rank(Capability::Mining, previous_epoch) .take(MINING_REPLICATION_FACTOR) diff --git a/node/src/actors/chain_manager/mining.rs b/node/src/actors/chain_manager/mining.rs index c904451cf..f19edddaf 100644 --- a/node/src/actors/chain_manager/mining.rs +++ b/node/src/actors/chain_manager/mining.rs @@ -1125,7 +1125,7 @@ pub fn build_block( } } - let protocol_version = get_protocol_version(Some(epoch)); + let protocol_version = ProtocolVersion::from_epoch(epoch); if protocol_version > V1_7 { let mut included_validators = HashSet::::new(); diff --git a/node/src/actors/chain_manager/mod.rs b/node/src/actors/chain_manager/mod.rs index 894c315ae..0f91645e2 100644 --- a/node/src/actors/chain_manager/mod.rs +++ b/node/src/actors/chain_manager/mod.rs @@ -809,7 +809,7 @@ impl ChainManager { } }; let protocol_version = - get_protocol_version(Some(block.block_header.beacon.checkpoint)); + ProtocolVersion::from_epoch(block.block_header.beacon.checkpoint); if let Some(best_candidate) = &self.best_candidate { let best_hash = best_candidate.block.hash(); @@ -1024,7 +1024,7 @@ impl ChainManager { let miner_pkh = block.block_header.proof.proof.pkh(); // Reset the coin age of the miner for all staked coins - if get_protocol_version(Some(block_epoch)) == ProtocolVersion::V2_0 { + if ProtocolVersion::from_epoch(block_epoch) == ProtocolVersion::V2_0 { let _ = stakes.reset_age(miner_pkh, Capability::Mining, current_epoch, 1); for co_tx in &block.txns.commit_txns { @@ -1552,7 +1552,7 @@ impl ChainManager { // than or equal to the current epoch block_epoch: current_epoch, }; - let protocol_version = get_protocol_version(Some(current_epoch)); + let protocol_version = ProtocolVersion::from_epoch(current_epoch); let collateral_age = if active_wips.wip0027() { PSEUDO_CONSENSUS_CONSTANTS_WIP0027_COLLATERAL_AGE } else { @@ -2097,7 +2097,7 @@ impl ChainManager { active_wips: self.chain_state.tapi_engine.wip_activation.clone(), block_epoch: block.block_header.beacon.checkpoint, }; - let protocol_version = get_protocol_version(Some(block.block_header.beacon.checkpoint)); + let protocol_version = ProtocolVersion::from_epoch(block.block_header.beacon.checkpoint); let res = validate_block( &block, current_epoch, @@ -4020,7 +4020,7 @@ mod tests { fn create_valid_block(chain_manager: &mut ChainManager, priv_key: &[u8; 32]) -> Block { let vrf = &mut VrfCtx::secp256k1().unwrap(); let current_epoch = chain_manager.current_epoch.unwrap(); - let protocol_version = get_protocol_version(Some(current_epoch)); + let protocol_version = ProtocolVersion::from_epoch(current_epoch); let consensus_constants = chain_manager.consensus_constants(); let secret_key = SecretKey { @@ -4069,7 +4069,7 @@ mod tests { }; let block_header = BlockHeader { - merkle_roots: BlockMerkleRoots::from_transactions(&txns), + merkle_roots: BlockMerkleRoots::from_transactions(&txns, protocol_version), beacon: block_beacon, proof: BlockEligibilityClaim::create(vrf, &secret_key, vrf_input).unwrap(), ..Default::default() diff --git a/node/src/actors/json_rpc/api.rs b/node/src/actors/json_rpc/api.rs index 6f5c9084b..9b0c02293 100644 --- a/node/src/actors/json_rpc/api.rs +++ b/node/src/actors/json_rpc/api.rs @@ -809,7 +809,7 @@ pub async fn get_block(params: Params) -> Result { "tally" : tt_hashes })); - if get_protocol_version(Some(block_epoch)) == ProtocolVersion::V2_0 { + if ProtocolVersion::from_epoch(block_epoch) == ProtocolVersion::V2_0 { let st_hashes: Vec<_> = output .txns .stake_txns @@ -862,7 +862,7 @@ pub async fn get_block(params: Params) -> Result { "data_request": drt_weights, })); - if get_protocol_version(Some(block_epoch)) == ProtocolVersion::V2_0 { + if ProtocolVersion::from_epoch(block_epoch) == ProtocolVersion::V2_0 { let st_weights: Vec<_> = output .txns .stake_txns diff --git a/validations/src/tests/mod.rs b/validations/src/tests/mod.rs index 03179d531..822892504 100644 --- a/validations/src/tests/mod.rs +++ b/validations/src/tests/mod.rs @@ -23,6 +23,7 @@ use witnet_data_structures::{ calculate_tally_change, calculate_witness_reward, create_tally, DataRequestPool, }, error::{BlockError, DataRequestError, Secp256k1ConversionError, TransactionError}, + get_protocol_version, proto::versioning::{ProtocolVersion, VersionedHashable}, radon_error::RadonError, radon_report::{RadonReport, ReportContext, TypeLike}, @@ -588,9 +589,9 @@ where F: FnMut(H, KeyedSignature) -> Result<(), failure::Error>, H: VersionedHashable + Clone, { - let version = ProtocolVersion::default(); - let ks = sign_tx(PRIV_KEY_1, &hashable, Some(version)); - let hash = hashable.versioned_hash(version); + let protocol_version = ProtocolVersion::guess(); + let ks = sign_tx(PRIV_KEY_1, &hashable, Some(protocol_version)); + let hash = hashable.versioned_hash(protocol_version); // Replace the signature with default (all zeros) let ks_default = KeyedSignature::default(); @@ -655,7 +656,7 @@ where ); // Sign transaction with a different public key - let ks_different_pk = sign_tx(PRIV_KEY_2, &hashable, None); + let ks_different_pk = sign_tx(PRIV_KEY_2, &hashable, Some(protocol_version)); let signature_pkh = ks_different_pk.public_key.pkh(); let x = f(hashable, ks_different_pk); assert_eq!( @@ -9127,7 +9128,7 @@ fn test_block_with_drpool_and_utxo_set bool>( }; let block_header = BlockHeader { - merkle_roots: BlockMerkleRoots::from_transactions(&txns), + merkle_roots: BlockMerkleRoots::from_transactions(&txns, protocol_version), beacon: block_beacon, proof: BlockEligibilityClaim::create(vrf, &secret_key, vrf_input).unwrap(), ..Default::default() @@ -9410,7 +9411,7 @@ fn block_difficult_proof() { }; let block_header = BlockHeader { - merkle_roots: BlockMerkleRoots::from_transactions(&txns), + merkle_roots: BlockMerkleRoots::from_transactions(&txns, protocol_version), beacon: block_beacon, proof: BlockEligibilityClaim::create(vrf, &secret_key, vrf_input).unwrap(), ..Default::default() @@ -9561,6 +9562,7 @@ fn block_duplicated_commits() { bytes: Protected::from(PRIV_KEY_1.to_vec()), }; let current_epoch = 1000; + let protocol_version = ProtocolVersion::from_epoch(current_epoch); let last_vrf_input = LAST_VRF_INPUT.parse().unwrap(); let vrf_input = CheckpointVRF { @@ -9608,7 +9610,7 @@ fn block_duplicated_commits() { cb.outputs = vec![]; // Sign commitment - let cs = sign_tx(PRIV_KEY_1, &cb, None); + let cs = sign_tx(PRIV_KEY_1, &cb, Some(protocol_version)); let c_tx = CommitTransaction::new(cb.clone(), vec![cs]); let mut cb2 = CommitTransactionBody::default(); @@ -9617,7 +9619,7 @@ fn block_duplicated_commits() { cb2.commitment = Hash::SHA256([1; 32]); cb2.collateral = vec![vti2]; cb2.outputs = vec![]; - let cs2 = sign_tx(PRIV_KEY_1, &cb2, None); + let cs2 = sign_tx(PRIV_KEY_1, &cb2, Some(protocol_version)); let c2_tx = CommitTransaction::new(cb2, vec![cs2]); assert_ne!(c_tx.hash(), c2_tx.hash()); @@ -9637,7 +9639,8 @@ fn block_duplicated_commits() { }], ); - b.block_header.merkle_roots = BlockMerkleRoots::from_transactions(&b.txns); + b.block_header.merkle_roots = + BlockMerkleRoots::from_transactions(&b.txns, protocol_version); true }, @@ -9669,18 +9672,29 @@ fn block_duplicated_reveals() { data_request: example_data_request(), collateral: DEFAULT_COLLATERAL, }; + let dr_epoch = 0; + let protocol_version = ProtocolVersion::from_epoch(dr_epoch); let dr_body = DRTransactionBody::new(vec![], dro, vec![]); - let drs = sign_tx(PRIV_KEY_1, &dr_body, None); + let drs = sign_tx(PRIV_KEY_1, &dr_body, Some(protocol_version)); let dr_transaction = DRTransaction::new(dr_body, vec![drs]); let dr_hash = dr_transaction.hash(); - let dr_epoch = 0; dr_pool .process_data_request(&dr_transaction, dr_epoch, &Hash::default()) .unwrap(); // Hack: get public key by signing an empty transaction - let public_key = sign_tx(PRIV_KEY_1, &RevealTransactionBody::default(), None).public_key; - let public_key2 = sign_tx(PRIV_KEY_2, &RevealTransactionBody::default(), None).public_key; + let public_key = sign_tx( + PRIV_KEY_1, + &RevealTransactionBody::default(), + Some(protocol_version), + ) + .public_key; + let public_key2 = sign_tx( + PRIV_KEY_2, + &RevealTransactionBody::default(), + Some(protocol_version), + ) + .public_key; let dr_pointer = dr_hash; @@ -9689,7 +9703,7 @@ fn block_duplicated_reveals() { let reveal_value = vec![0x00]; let reveal_body = RevealTransactionBody::new(dr_pointer, reveal_value.clone(), public_key.pkh()); - let reveal_signature = sign_tx(PRIV_KEY_1, &reveal_body, None); + let reveal_signature = sign_tx(PRIV_KEY_1, &reveal_body, Some(protocol_version)); let commitment = reveal_signature.signature.hash(); let commit_transaction = CommitTransaction::new( @@ -9745,7 +9759,8 @@ fn block_duplicated_reveals() { }], ); - b.block_header.merkle_roots = BlockMerkleRoots::from_transactions(&b.txns); + b.block_header.merkle_roots = + BlockMerkleRoots::from_transactions(&b.txns, protocol_version); true }, @@ -9768,6 +9783,7 @@ fn block_duplicated_tallies() { let dr_output = example_data_request_output(2, DEFAULT_WITNESS_REWARD, 20); let (dr_pool, dr_pointer, rewarded, slashed, error_witnesses, _dr_pkh, _change, reward) = dr_pool_with_dr_in_tally_stage(dr_output, 2, 2, 0, reveal_value, vec![], active_wips); + let protocol_version = ProtocolVersion::guess(); // You earn your reward, and get your collateral back assert_eq!(reward, DEFAULT_WITNESS_REWARD + DEFAULT_COLLATERAL); @@ -9814,7 +9830,8 @@ fn block_duplicated_tallies() { }], ); - b.block_header.merkle_roots = BlockMerkleRoots::from_transactions(&b.txns); + b.block_header.merkle_roots = + BlockMerkleRoots::from_transactions(&b.txns, protocol_version); true }, @@ -9842,6 +9859,7 @@ fn block_before_and_after_hard_fork() { let drs = sign_tx(PRIV_KEY_1, &dr_body, None); let dr_transaction = DRTransaction::new(dr_body, vec![drs]); let dr_epoch = 0; + let protocol_version = ProtocolVersion::from_epoch(dr_epoch); dr_pool .process_data_request(&dr_transaction, dr_epoch, &Hash::default()) .unwrap(); @@ -9872,7 +9890,8 @@ fn block_before_and_after_hard_fork() { }], ); - b.block_header.merkle_roots = BlockMerkleRoots::from_transactions(&b.txns); + b.block_header.merkle_roots = + BlockMerkleRoots::from_transactions(&b.txns, protocol_version); true }, @@ -9895,7 +9914,8 @@ fn block_before_and_after_hard_fork() { }], ); - b.block_header.merkle_roots = BlockMerkleRoots::from_transactions(&b.txns); + b.block_header.merkle_roots = + BlockMerkleRoots::from_transactions(&b.txns, protocol_version); true }, @@ -10124,7 +10144,7 @@ fn test_blocks_with_limits( hash_prev_block: last_block_hash, }; let block_header = BlockHeader { - merkle_roots: BlockMerkleRoots::from_transactions(&txns), + merkle_roots: BlockMerkleRoots::from_transactions(&txns, protocol_version), beacon: block_beacon, proof: BlockEligibilityClaim::create(vrf, &secret_key, vrf_input).unwrap(), ..Default::default() @@ -10132,7 +10152,7 @@ fn test_blocks_with_limits( let block_sig = KeyedSignature::default(); let mut b = Block::new(block_header, block_sig, txns); - b.block_sig = sign_tx(PRIV_KEY_1, &b.block_header, None); + b.block_sig = sign_tx(PRIV_KEY_1, &b.block_header, Some(protocol_version)); let mut signatures_to_verify = vec![]; @@ -10926,7 +10946,7 @@ fn validate_block_transactions_uses_block_number_in_utxo_diff() { }; let block_header = BlockHeader { - merkle_roots: BlockMerkleRoots::from_transactions(&txns), + merkle_roots: BlockMerkleRoots::from_transactions(&txns, protocol_version), beacon: block_beacon, proof: BlockEligibilityClaim::create(vrf, &secret_key, vrf_input).unwrap(), ..Default::default() @@ -11095,12 +11115,12 @@ fn validate_commit_transactions_included_in_utxo_diff() { txns.commit_txns.push(c_tx); let block_header = BlockHeader { - merkle_roots: BlockMerkleRoots::from_transactions(&txns), + merkle_roots: BlockMerkleRoots::from_transactions(&txns, protocol_version), beacon: block_beacon, proof: BlockEligibilityClaim::create(vrf, &secret_key, vrf_input).unwrap(), ..Default::default() }; - let block_sig = sign_tx(PRIV_KEY_1, &block_header, None); + let block_sig = sign_tx(PRIV_KEY_1, &block_header, Some(protocol_version)); let b = Block::new(block_header, block_sig, txns); let mut signatures_to_verify = vec![]; diff --git a/validations/src/validations.rs b/validations/src/validations.rs index e27f0482c..c59ccfe3f 100644 --- a/validations/src/validations.rs +++ b/validations/src/validations.rs @@ -319,7 +319,7 @@ pub fn validate_mint_transaction( .into()); } - if get_protocol_version(Some(block_epoch)) != ProtocolVersion::V2_0 { + if ProtocolVersion::from_epoch(block_epoch) != ProtocolVersion::V2_0 { let mint_value = transaction_outputs_sum(&mint_tx.outputs)?; let block_reward_value = block_reward(mint_tx.epoch, initial_block_reward, halving_period); // Mint value must be equal to block_reward + transaction fees @@ -556,7 +556,7 @@ pub fn validate_dr_transaction<'a>( // A value transfer output cannot have zero value if dr_output.value == 0 { return Err(TransactionError::ZeroValueOutput { - tx_hash: dr_tx.hash(), + tx_hash: dr_tx.versioned_hash(protocol_version), output_id: 0, } .into()); @@ -2007,7 +2007,7 @@ pub fn validate_block_transactions( consensus_constants.max_dr_weight, required_reward_collateral_ratio, active_wips, - None, + Some(protocol_version), )?; total_fee += fee; diff --git a/wallet/src/actors/worker/methods.rs b/wallet/src/actors/worker/methods.rs index 407ae8949..c03e2ecd7 100644 --- a/wallet/src/actors/worker/methods.rs +++ b/wallet/src/actors/worker/methods.rs @@ -986,7 +986,7 @@ impl Worker { let wallet_data = wallet.public_data()?; let last_sync = wallet_data.last_sync; let last_confirmed = wallet_data.last_confirmed; - let protocol_version = get_protocol_version(Some(block_beacon.checkpoint)); + let protocol_version = ProtocolVersion::from_epoch(block_beacon.checkpoint); let (needs_clear_pending, needs_indexing) = if block_beacon.hash_prev_block == last_sync.hash_prev_block && (block_beacon.checkpoint == 0 || block_beacon.checkpoint > last_sync.checkpoint)