diff --git a/Cargo.lock b/Cargo.lock index 2ed12d7385..13541474cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,18 +63,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "ahash" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.2" @@ -497,47 +485,26 @@ dependencies = [ [[package]] name = "borsh" -version = "0.10.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +checksum = "bf617fabf5cdbdc92f774bfe5062d870f228b80056d41180797abf48bed4056e" dependencies = [ "borsh-derive", - "hashbrown 0.13.2", + "cfg_aliases", ] [[package]] name = "borsh-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" -dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", - "proc-macro-crate 0.1.5", - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "borsh-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "borsh-schema-derive-internal" -version = "0.10.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" +checksum = "f404657a7ea7b5249e36808dff544bc88a28f26e0ac40009f674b7a009d14be3" dependencies = [ + "once_cell", + "proc-macro-crate 2.0.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.38", + "syn_derive", ] [[package]] @@ -692,6 +659,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "chacha20" version = "0.7.3" @@ -2226,16 +2199,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.7", -] - -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash 0.8.6", + "ahash", ] [[package]] @@ -3439,7 +3403,7 @@ dependencies = [ "sealed 0.4.0", "serde", "thiserror", - "tiny-keccak", + "tiny-keccak 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4257,21 +4221,21 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "0.1.5" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ + "thiserror", "toml 0.5.11", ] [[package]] name = "proc-macro-crate" -version = "1.1.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" dependencies = [ - "thiserror", - "toml 0.5.11", + "toml_edit 0.20.7", ] [[package]] @@ -5462,6 +5426,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "sync_wrapper" version = "0.1.2" @@ -5873,6 +5849,7 @@ dependencies = [ "tari_utilities", "tempfile", "thiserror", + "tiny-keccak 2.0.2 (git+https://github.com/tari-project/tiny-keccak?rev=bcddc65530d8646de7282cd8d18d891dc434b643)", "tokio", "toml 0.5.11", "tracing", @@ -5881,9 +5858,9 @@ dependencies = [ [[package]] name = "tari_crypto" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c74907b0c0237bc545e1da9b3ad6654fff934bdbd291bbe2a0e57e61933d6fc4" +checksum = "f5f92a2fc36466fb0653a67671fd62ebadadc69cecd0b240bd40cc76150ff488" dependencies = [ "blake2", "borsh", @@ -6144,9 +6121,9 @@ dependencies = [ [[package]] name = "tari_utilities" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c396f014de7fa290ea8decd7238df9f1c175f243480a4ebef9ec61f144b1c95" +checksum = "387dd7a5067310780c64c0e00288ab65b38f8899d8913ee6df3645bc59711c24" dependencies = [ "base58-monero 0.3.2", "base64 0.13.1", @@ -6291,6 +6268,15 @@ dependencies = [ "crunchy", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "git+https://github.com/tari-project/tiny-keccak?rev=bcddc65530d8646de7282cd8d18d891dc434b643#bcddc65530d8646de7282cd8d18d891dc434b643" +dependencies = [ + "borsh", + "crunchy", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -6447,7 +6433,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.19.15", ] [[package]] @@ -6472,6 +6458,17 @@ dependencies = [ "winnow", ] +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + [[package]] name = "tonic" version = "0.6.2" @@ -7347,26 +7344,6 @@ dependencies = [ "time", ] -[[package]] -name = "zerocopy" -version = "0.7.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686b7e407015242119c33dab17b8f61ba6843534de936d94368856528eae4dcc" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020f3dfe25dfc38dfea49ce62d5d45ecdd7f0d8a724fa63eb36b6eba4ec76806" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - [[package]] name = "zeroize" version = "1.6.0" diff --git a/applications/minotari_app_grpc/Cargo.toml b/applications/minotari_app_grpc/Cargo.toml index 25c0dbb9f9..7cf191e511 100644 --- a/applications/minotari_app_grpc/Cargo.toml +++ b/applications/minotari_app_grpc/Cargo.toml @@ -11,13 +11,13 @@ edition = "2018" tari_common_types = { path = "../../base_layer/common_types" } tari_comms = { path = "../../comms/core" } tari_core = { path = "../../base_layer/core" } -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } tari_script = { path = "../../infrastructure/tari_script" } tari_utilities = { version = "0.6" } argon2 = { version = "0.4.1", features = ["std", "password-hash"] } base64 = "0.13.0" -borsh = "0.10" +borsh = "1.2" chrono = { version = "0.4.19", default-features = false } log = "0.4" prost = "0.9" diff --git a/applications/minotari_app_grpc/src/conversions/transaction_input.rs b/applications/minotari_app_grpc/src/conversions/transaction_input.rs index ca45cbbcee..f93b6e7173 100644 --- a/applications/minotari_app_grpc/src/conversions/transaction_input.rs +++ b/applications/minotari_app_grpc/src/conversions/transaction_input.rs @@ -22,7 +22,6 @@ use std::convert::{TryFrom, TryInto}; -use borsh::BorshSerialize; use tari_common_types::types::{Commitment, PublicKey}; use tari_core::{ borsh::FromBytes, @@ -144,11 +143,12 @@ impl TryFrom for grpc::TransactionInput { .map_err(|_| "Non-compact Transaction input should contain sender_offset_public_key".to_string())? .to_vec(), output_hash: Vec::new(), - covenant: input - .covenant() - .map_err(|_| "Non-compact Transaction input should contain covenant".to_string())? - .try_to_vec() - .map_err(|err| err.to_string())?, + covenant: borsh::to_vec( + &input + .covenant() + .map_err(|_| "Non-compact Transaction input should contain covenant".to_string())?, + ) + .map_err(|err| err.to_string())?, version: input.version as u32, encrypted_data: input .encrypted_data() diff --git a/applications/minotari_console_wallet/Cargo.toml b/applications/minotari_console_wallet/Cargo.toml index 655ad8fee4..2dd3a3e4e5 100644 --- a/applications/minotari_console_wallet/Cargo.toml +++ b/applications/minotari_console_wallet/Cargo.toml @@ -13,7 +13,7 @@ tari_common_types = { path = "../../base_layer/common_types" } tari_comms = { path = "../../comms/core" } tari_comms_dht = { path = "../../comms/dht" } tari_contacts = { path = "../../base_layer/contacts" } -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } tari_key_manager = { path = "../../base_layer/key_manager" } tari_libtor = { path = "../../infrastructure/libtor", optional = true } tari_p2p = { path = "../../base_layer/p2p", features = ["auto-update"] } diff --git a/applications/minotari_merge_mining_proxy/Cargo.toml b/applications/minotari_merge_mining_proxy/Cargo.toml index 27b8c90a37..88fa19baea 100644 --- a/applications/minotari_merge_mining_proxy/Cargo.toml +++ b/applications/minotari_merge_mining_proxy/Cargo.toml @@ -25,7 +25,7 @@ tari_key_manager = { path = "../../base_layer/key_manager", features = ["key_ma anyhow = "1.0.53" crossterm = { version = "0.25.0" } bincode = "1.3.1" -borsh = "0.10" +borsh = "1.2" bytes = "1.1" chrono = { version = "0.4.6", default-features = false } clap = { version = "3.2", features = ["derive", "env"] } diff --git a/applications/minotari_merge_mining_proxy/src/proxy.rs b/applications/minotari_merge_mining_proxy/src/proxy.rs index 3f062d18c7..859b773ebf 100644 --- a/applications/minotari_merge_mining_proxy/src/proxy.rs +++ b/applications/minotari_merge_mining_proxy/src/proxy.rs @@ -283,7 +283,7 @@ impl InnerService { let start = Instant::now(); let achieved_target = if self.config.check_tari_difficulty_before_submit { trace!(target: LOG_TARGET, "Starting calculate achieved Tari difficultly"); - let diff = randomx_difficulty(&tari_header, &self.randomx_factory, &gen_hash)?; + let diff = randomx_difficulty(&tari_header, &self.randomx_factory, &gen_hash, &self.consensus_manager)?; trace!( target: LOG_TARGET, "Finished calculate achieved Tari difficultly - achieved {} vs. target {}", diff --git a/applications/minotari_miner/Cargo.toml b/applications/minotari_miner/Cargo.toml index d12aeb2de4..d75f10a7da 100644 --- a/applications/minotari_miner/Cargo.toml +++ b/applications/minotari_miner/Cargo.toml @@ -14,11 +14,11 @@ tari_common_types = { path = "../../base_layer/common_types" } tari_comms = { path = "../../comms/core" } minotari_app_utilities = { path = "../minotari_app_utilities" } minotari_app_grpc = { path = "../minotari_app_grpc" } -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } tari_utilities = { version = "0.6" } base64 = "0.13.0" -borsh = "0.10" +borsh = "1.2" bufstream = "0.1" chrono = { version = "0.4.19", default-features = false } clap = { version = "3.2", features = ["derive"] } diff --git a/applications/minotari_node/Cargo.toml b/applications/minotari_node/Cargo.toml index de24bc4bc2..acd7c930ce 100644 --- a/applications/minotari_node/Cargo.toml +++ b/applications/minotari_node/Cargo.toml @@ -15,7 +15,7 @@ tari_comms = { path = "../../comms/core", features = ["rpc"] } tari_common_types = { path = "../../base_layer/common_types" } tari_comms_dht = { path = "../../comms/dht" } tari_core = { path = "../../base_layer/core", default-features = false, features = ["transactions"] } -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } tari_libtor = { path = "../../infrastructure/libtor", optional = true } tari_p2p = { path = "../../base_layer/p2p", features = ["auto-update"] } tari_storage = {path="../../infrastructure/storage"} @@ -26,7 +26,7 @@ tari_utilities = { version = "0.6" } anyhow = "1.0.53" async-trait = "0.1.52" bincode = "1.3.1" -borsh = "0.10" +borsh = "1.2" chrono = { version = "0.4.19", default-features = false } clap = { version = "3.2", features = ["derive", "env"] } console-subscriber = "0.1.8" diff --git a/base_layer/chat_ffi/Cargo.toml b/base_layer/chat_ffi/Cargo.toml index 340a2c7d96..778c79fe81 100644 --- a/base_layer/chat_ffi/Cargo.toml +++ b/base_layer/chat_ffi/Cargo.toml @@ -32,7 +32,7 @@ crate-type = ["staticlib","cdylib"] [dev-dependencies] chrono = { version = "0.4.19", default-features = false } rand = "0.8" -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } [build-dependencies] cbindgen = "0.24.3" diff --git a/base_layer/common_types/Cargo.toml b/base_layer/common_types/Cargo.toml index 45e5e39180..9af472cfec 100644 --- a/base_layer/common_types/Cargo.toml +++ b/base_layer/common_types/Cargo.toml @@ -7,13 +7,13 @@ version = "0.53.0-pre.0" edition = "2018" [dependencies] -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } tari_utilities = { version = "0.6" } tari_common = { path = "../../common" } chacha20poly1305 = "0.10.1" -borsh = "0.10" +borsh = "1.2" digest = "0.10" newtype-ops = "0.1" once_cell = "1.8.0" diff --git a/base_layer/contacts/Cargo.toml b/base_layer/contacts/Cargo.toml index a6df76bd3e..04314c7126 100644 --- a/base_layer/contacts/Cargo.toml +++ b/base_layer/contacts/Cargo.toml @@ -12,7 +12,7 @@ tari_common_sqlite = { path = "../../common_sqlite" } tari_common_types = { path = "../../base_layer/common_types" } tari_comms = { path = "../../comms/core" } tari_comms_dht = { path = "../../comms/dht" } -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } tari_p2p = { path = "../p2p", features = ["auto-update"] } tari_service_framework = { path = "../service_framework" } tari_shutdown = { path = "../../infrastructure/shutdown" } diff --git a/base_layer/core/Cargo.toml b/base_layer/core/Cargo.toml index 5a0d9c7c39..9292a3dd9b 100644 --- a/base_layer/core/Cargo.toml +++ b/base_layer/core/Cargo.toml @@ -24,7 +24,7 @@ tari_common_types = { path = "../../base_layer/common_types" } tari_comms = { path = "../../comms/core" } tari_comms_dht = { path = "../../comms/dht" } tari_comms_rpc_macros = { path = "../../comms/rpc_macros" } -tari_crypto = { version = "0.19", features = ["borsh"] } +tari_crypto = { version = "0.19.1", features = ["borsh"] } tari_metrics = { path = "../../infrastructure/metrics", optional = true } tari_mmr = { path = "../../base_layer/mmr", optional = true} tari_p2p = { path = "../../base_layer/p2p" } @@ -41,7 +41,7 @@ async-trait = {version = "0.1.50"} bincode = "1.1.4" bitflags = { version = "2.4", features = ["serde"] } blake2 = "0.10" -borsh = { version = "0.10", features = ["const-generics"] } +borsh = { version = "1.2", features = ["derive"] } bytes = "0.5" chacha20poly1305 = "0.10.1" chrono = { version = "0.4.19", default-features = false, features = ["serde"] } @@ -51,7 +51,7 @@ digest = "0.10" fs2 = "0.4.0" futures = { version = "^0.3.16", features = ["async-await"] } hex = "0.4.2" -integer-encoding = "3.0.2" +integer-encoding = "3.0" lmdb-zero = "0.4.4" log = "0.4" log-mdc = "0.1.0" @@ -76,6 +76,7 @@ tokio = { version = "1.23", features = ["time", "sync", "macros"] } tracing = "0.1.26" zeroize = "1" primitive-types = { version = "0.12", features = ["serde"] } +tiny-keccak = { git = "https://github.com/tari-project/tiny-keccak", rev = "bcddc65530d8646de7282cd8d18d891dc434b643",features = ["keccak"] } [dev-dependencies] criterion = { version = "0.4.0" } diff --git a/base_layer/core/src/base_node/comms_interface/inbound_handlers.rs b/base_layer/core/src/base_node/comms_interface/inbound_handlers.rs index 8077c6db73..4acbbff490 100644 --- a/base_layer/core/src/base_node/comms_interface/inbound_handlers.rs +++ b/base_layer/core/src/base_node/comms_interface/inbound_handlers.rs @@ -526,7 +526,12 @@ where B: BlockchainBackend + 'static .await?; } let achieved = match new_block.header.pow_algo() { - PowAlgorithm::RandomX => randomx_difficulty(&new_block.header, &self.randomx_factory, &gen_hash)?, + PowAlgorithm::RandomX => randomx_difficulty( + &new_block.header, + &self.randomx_factory, + &gen_hash, + &self.consensus_manager, + )?, PowAlgorithm::Sha3x => sha3x_difficulty(&new_block.header)?, }; if achieved < min_difficulty { diff --git a/base_layer/core/src/chain_storage/blockchain_database.rs b/base_layer/core/src/chain_storage/blockchain_database.rs index 7781cf85d4..b9266984bc 100644 --- a/base_layer/core/src/chain_storage/blockchain_database.rs +++ b/base_layer/core/src/chain_storage/blockchain_database.rs @@ -1023,8 +1023,9 @@ where B: BlockchainBackend fn insert_block(&self, block: Arc) -> Result<(), ChainStorageError> { let mut db = self.db_write_access()?; + let mut txn = DbTransaction::new(); - insert_best_block(&mut txn, block)?; + insert_best_block(&mut txn, block, &self.consensus_manager)?; db.write(txn) } @@ -1182,6 +1183,7 @@ where B: BlockchainBackend &self.config, &*self.validators.block, self.consensus_manager.chain_strength_comparer(), + &self.consensus_manager, )?; Ok(()) } @@ -1467,7 +1469,11 @@ fn add_block( } /// Adds a new block onto the chain tip and sets it to the best block. -fn insert_best_block(txn: &mut DbTransaction, block: Arc) -> Result<(), ChainStorageError> { +fn insert_best_block( + txn: &mut DbTransaction, + block: Arc, + consensus: &ConsensusManager, +) -> Result<(), ChainStorageError> { let block_hash = block.accumulated_data().hash; debug!( target: LOG_TARGET, @@ -1477,7 +1483,7 @@ fn insert_best_block(txn: &mut DbTransaction, block: Arc) -> Result< ); if block.header().pow_algo() == PowAlgorithm::RandomX { let monero_header = - MoneroPowData::from_header(block.header()).map_err(|e| ChainStorageError::InvalidArguments { + MoneroPowData::from_header(block.header(), consensus).map_err(|e| ChainStorageError::InvalidArguments { func: "insert_best_block", arg: "block", message: format!("block contained invalid or malformed monero PoW data: {}", e), @@ -1822,7 +1828,7 @@ fn handle_possible_reorg( let hash = candidate_block.header.hash(); insert_orphan_and_find_new_tips(db, candidate_block, header_validator, consensus_manager)?; let after_orphans = timer.elapsed(); - let res = swap_to_highest_pow_chain(db, config, block_validator, chain_strength_comparer); + let res = swap_to_highest_pow_chain(db, config, block_validator, chain_strength_comparer, consensus_manager); trace!( target: LOG_TARGET, "[handle_possible_reorg] block #{}, insert_orphans in {:.2?}, swap_to_highest in {:.2?} '{}'", @@ -1841,6 +1847,7 @@ fn reorganize_chain( block_validator: &dyn CandidateBlockValidator, fork_hash: HashOutput, chain: &VecDeque>, + consensus: &ConsensusManager, ) -> Result>, ChainStorageError> { let removed_blocks = rewind_to_hash(backend, fork_hash)?; debug!( @@ -1872,11 +1879,11 @@ fn reorganize_chain( remove_orphan(backend, block_hash)?; info!(target: LOG_TARGET, "Restoring previous chain after failed reorg."); - restore_reorged_chain(backend, fork_hash, removed_blocks)?; + restore_reorged_chain(backend, fork_hash, removed_blocks, consensus)?; return Err(e.into()); } - insert_best_block(&mut txn, block.clone())?; + insert_best_block(&mut txn, block.clone(), consensus)?; // Failed to store the block - this should typically never happen unless there is a bug in the validator // (e.g. does not catch a double spend). In any case, we still need to restore the chain to a // good state before returning. @@ -1886,7 +1893,7 @@ fn reorganize_chain( "Failed to commit reorg chain: {:?}. Restoring last chain.", e ); - restore_reorged_chain(backend, fork_hash, removed_blocks)?; + restore_reorged_chain(backend, fork_hash, removed_blocks, consensus)?; return Err(e); } } @@ -1899,6 +1906,7 @@ fn swap_to_highest_pow_chain( config: &BlockchainDatabaseConfig, block_validator: &dyn CandidateBlockValidator, chain_strength_comparer: &dyn ChainStrengthComparer, + consensus: &ConsensusManager, ) -> Result { let metadata = db.fetch_chain_metadata()?; // lets clear out all remaining headers that dont have a matching block @@ -1955,7 +1963,7 @@ fn swap_to_highest_pow_chain( .prev_hash; let num_added_blocks = reorg_chain.len(); - let removed_blocks = reorganize_chain(db, block_validator, fork_hash, &reorg_chain)?; + let removed_blocks = reorganize_chain(db, block_validator, fork_hash, &reorg_chain, consensus)?; let num_removed_blocks = removed_blocks.len(); // reorg is required when any blocks are removed or more than one are added @@ -2007,6 +2015,7 @@ fn restore_reorged_chain( db: &mut T, to_hash: HashOutput, previous_chain: Vec>, + consensus: &ConsensusManager, ) -> Result<(), ChainStorageError> { let invalid_chain = rewind_to_hash(db, to_hash)?; debug!( @@ -2022,7 +2031,7 @@ fn restore_reorged_chain( for block in previous_chain.into_iter().rev() { txn.delete_orphan(block.accumulated_data().hash); - insert_best_block(&mut txn, block)?; + insert_best_block(&mut txn, block, consensus)?; } db.write(txn)?; Ok(()) diff --git a/base_layer/core/src/consensus/consensus_constants.rs b/base_layer/core/src/consensus/consensus_constants.rs index d499d51c0d..8405387105 100644 --- a/base_layer/core/src/consensus/consensus_constants.rs +++ b/base_layer/core/src/consensus/consensus_constants.rs @@ -82,6 +82,8 @@ pub struct ConsensusConstants { /// This is the maximum age a Monero merge mined seed can be reused /// Monero forces a change every height mod 2048 blocks max_randomx_seed_height: u64, + /// Monero Coinbases are unlimited in size, but we limited the extra field to only a certain bytes. + max_extra_field_size: usize, /// This keeps track of the block split targets and which algo is accepted /// Ideally this should count up to 100. If this does not you will reduce your target time. proof_of_work: HashMap, @@ -200,6 +202,11 @@ impl ConsensusConstants { Utc::now().add(Duration::seconds(self.future_time_limit as i64)) } + /// Monero Coinbases are unlimited in size, but we limited the extra field to only a certain bytes. + pub fn max_extra_field_size(&self) -> usize { + self.max_extra_field_size + } + /// When doing difficulty adjustments and FTL calculations this is the amount of blocks we look at. pub fn difficulty_block_window(&self) -> u64 { self.difficulty_block_window @@ -371,6 +378,7 @@ impl ConsensusConstants { emission_decay: &ESMERALDA_DECAY_PARAMS, emission_tail: 800 * T, max_randomx_seed_height: u64::MAX, + max_extra_field_size: 200, proof_of_work: algos, faucet_value: ESMERALDA_FAUCET_VALUE.into(), // The esmeralda genesis block is re-used for localnet transaction_weight: TransactionWeight::latest(), @@ -433,6 +441,7 @@ impl ConsensusConstants { emission_decay: &EMISSION_DECAY, emission_tail: 100.into(), max_randomx_seed_height: u64::MAX, + max_extra_field_size: 200, proof_of_work: algos, faucet_value: 0.into(), // 1_195_651_566_094_148.into(), transaction_weight: TransactionWeight::v1(), @@ -488,6 +497,7 @@ impl ConsensusConstants { emission_decay: &ESMERALDA_DECAY_PARAMS, emission_tail: 800 * T, max_randomx_seed_height: 3000, + max_extra_field_size: 200, proof_of_work: algos, faucet_value: 0.into(), // ESMERALDA_FAUCET_VALUE.into(), transaction_weight: TransactionWeight::v1(), @@ -542,6 +552,7 @@ impl ConsensusConstants { emission_decay: &EMISSION_DECAY, emission_tail: 800 * T, max_randomx_seed_height: 3000, + max_extra_field_size: 200, proof_of_work: algos, faucet_value: 0.into(), /* ESMERALDA_FAUCET_VALUE.into(), // The esmeralda genesis block is re-used for * stagenet */ @@ -591,6 +602,7 @@ impl ConsensusConstants { emission_decay: &EMISSION_DECAY, emission_tail: 800 * T, max_randomx_seed_height: 3000, + max_extra_field_size: 200, proof_of_work: algos, faucet_value: 0.into(), /* ESMERALDA_FAUCET_VALUE.into(), // The esmeralda genesis block is re-used for * stagenet */ @@ -642,6 +654,7 @@ impl ConsensusConstants { emission_decay: &EMISSION_DECAY, emission_tail: 100.into(), max_randomx_seed_height: u64::MAX, + max_extra_field_size: 200, proof_of_work: algos, faucet_value: MicroMinotari::from(0), transaction_weight: TransactionWeight::v1(), diff --git a/base_layer/core/src/covenants/fields.rs b/base_layer/core/src/covenants/fields.rs index d53293ffb3..480dd0a6b4 100644 --- a/base_layer/core/src/covenants/fields.rs +++ b/base_layer/core/src/covenants/fields.rs @@ -46,6 +46,7 @@ use crate::{ #[derive(Debug, Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize)] #[repr(u8)] +#[borsh(use_discriminant = true)] /// Output field pub enum OutputField { Commitment = byte_codes::FIELD_COMMITMENT, @@ -605,10 +606,10 @@ mod test { let mut hasher = Blake2b::::default(); BaseLayerCovenantsDomain::add_domain_separation_tag(&mut hasher, COVENANTS_FIELD_HASHER_LABEL); let expected_hash = hasher - .chain(output.features.try_to_vec().unwrap()) - .chain(output.commitment.try_to_vec().unwrap()) - .chain(output.script.try_to_vec().unwrap()) - .chain(output.minimum_value_promise.try_to_vec().unwrap()) + .chain(borsh::to_vec(&output.features).unwrap()) + .chain(borsh::to_vec(&output.commitment).unwrap()) + .chain(borsh::to_vec(&output.script).unwrap()) + .chain(borsh::to_vec(&output.minimum_value_promise).unwrap()) .finalize() .to_vec(); assert_eq!(hash, expected_hash); diff --git a/base_layer/core/src/covenants/filters/fields_hashed_eq.rs b/base_layer/core/src/covenants/filters/fields_hashed_eq.rs index 6cbb9a0d5c..c9c1fe40d7 100644 --- a/base_layer/core/src/covenants/filters/fields_hashed_eq.rs +++ b/base_layer/core/src/covenants/filters/fields_hashed_eq.rs @@ -45,7 +45,6 @@ impl Filter for FieldsHashedEqFilter { #[cfg(test)] mod test { use blake2::Blake2b; - use borsh::BorshSerialize; use digest::{consts::U32, Update}; use tari_crypto::hashing::DomainSeparation; @@ -71,7 +70,7 @@ mod test { }; let mut hasher = Blake2b::::new(); BaseLayerCovenantsDomain::add_domain_separation_tag(&mut hasher, COVENANTS_FIELD_HASHER_LABEL); - let hash = hasher.chain(features.try_to_vec().unwrap()).finalize(); + let hash = hasher.chain(borsh::to_vec(&features).unwrap()).finalize(); let covenant = covenant!(fields_hashed_eq(@fields(@field::features), @hash(hash.into()))); let input = create_input(&key_manager).await; let (mut context, outputs) = setup_filter_test( diff --git a/base_layer/core/src/proof_of_work/monero_rx/helpers.rs b/base_layer/core/src/proof_of_work/monero_rx/helpers.rs index 1e0212f722..ab5b34150b 100644 --- a/base_layer/core/src/proof_of_work/monero_rx/helpers.rs +++ b/base_layer/core/src/proof_of_work/monero_rx/helpers.rs @@ -25,6 +25,7 @@ use log::*; use monero::{ blockdata::transaction::{ExtraField, RawExtraField, SubField}, consensus, + consensus::Encodable, cryptonote::hash::Hashable, VarInt, }; @@ -32,6 +33,7 @@ use primitive_types::U256; use sha2::{Digest, Sha256}; use tari_common_types::types::FixedHash; use tari_utilities::hex::HexError; +use tiny_keccak::{Hasher, Keccak}; use super::{ error::MergeMineError, @@ -41,6 +43,7 @@ use super::{ }; use crate::{ blocks::BlockHeader, + consensus::ConsensusManager, proof_of_work::{ monero_rx::merkle_tree_parameters::MerkleTreeParameters, randomx_factory::{RandomXFactory, RandomXVMInstance}, @@ -55,8 +58,9 @@ pub fn randomx_difficulty( header: &BlockHeader, randomx_factory: &RandomXFactory, gen_hash: &FixedHash, + consensus: &ConsensusManager, ) -> Result { - let monero_pow_data = verify_header(header, gen_hash)?; + let monero_pow_data = verify_header(header, gen_hash, consensus)?; debug!(target: LOG_TARGET, "Valid Monero data: {}", monero_pow_data); let blockhashing_blob = monero_pow_data.to_blockhashing_blob(); let vm = randomx_factory.create(monero_pow_data.randomx_key())?; @@ -94,10 +98,14 @@ fn parse_extra_field_truncate_on_error(raw_extra_field: &RawExtraField) -> Extra /// 1. The merkle proof and coinbase hash produce a matching merkle root /// /// If these assertions pass, a valid `MoneroPowData` instance is returned -pub fn verify_header(header: &BlockHeader, gen_hash: &FixedHash) -> Result { - let monero_data = MoneroPowData::from_header(header)?; +pub fn verify_header( + header: &BlockHeader, + gen_hash: &FixedHash, + consensus: &ConsensusManager, +) -> Result { + let monero_data = MoneroPowData::from_header(header, consensus)?; let expected_merge_mining_hash = header.merge_mining_hash(); - let extra_field = ExtraField::try_parse(&monero_data.coinbase_tx.prefix.extra) + let extra_field = ExtraField::try_parse(&monero_data.coinbase_tx_extra) .map_err(|_| MergeMineError::DeserializeError("Invalid extra field".to_string()))?; // Check that the Tari MM hash is found in the Monero coinbase transaction // and that only 1 Tari header is found @@ -232,6 +240,31 @@ pub fn construct_monero_data( .to_string(), ) })?; + let coinbase = block.miner_tx.clone(); + + let mut keccak = Keccak::v256(); + let mut encoder_prefix = Vec::new(); + coinbase + .prefix + .version + .consensus_encode(&mut encoder_prefix) + .map_err(|e| MergeMineError::SerializeError(e.to_string()))?; + coinbase + .prefix + .unlock_time + .consensus_encode(&mut encoder_prefix) + .map_err(|e| MergeMineError::SerializeError(e.to_string()))?; + coinbase + .prefix + .inputs + .consensus_encode(&mut encoder_prefix) + .map_err(|e| MergeMineError::SerializeError(e.to_string()))?; + coinbase + .prefix + .outputs + .consensus_encode(&mut encoder_prefix) + .map_err(|e| MergeMineError::SerializeError(e.to_string()))?; + keccak.update(&encoder_prefix); let t_hash = monero::Hash::from_slice(tari_hash.as_slice()); let aux_chain_merkle_proof = create_merkle_proof(&ordered_aux_chain_hashes, &t_hash).ok_or_else(|| { @@ -246,7 +279,8 @@ pub fn construct_monero_data( transaction_count: hashes.len() as u16, merkle_root: root, coinbase_merkle_proof, - coinbase_tx: block.miner_tx, + coinbase_tx_extra: block.miner_tx.prefix.extra, + coinbase_tx_hasher: keccak, aux_chain_merkle_proof, }) } @@ -357,6 +391,7 @@ mod test { TxIn, TxOut, }; + use tari_common::configuration::Network; use tari_common_types::types::FixedHash; use tari_test_utils::unpack_enum; use tari_utilities::{ @@ -449,11 +484,61 @@ mod test { assert_eq!(hex, hex2); } + #[test] + fn test_monero_partial_hash() { + let blocktemplate_blob = "0c0c8cd6a0fa057fe21d764e7abf004e975396a2160773b93712bf6118c3b4959ddd8ee0f76aad0000000002e1ea2701ffa5ea2701d5a299e2abb002028eb3066ced1b2cc82ea046f3716a48e9ae37144057d5fb48a97f941225a1957b2b0106225b7ec0a6544d8da39abe68d8bd82619b4a7c5bdae89c3783b256a8fa47820208f63aa86d2e857f070000".to_string(); + let bytes = hex::decode(blocktemplate_blob).unwrap(); + let mut block = deserialize::(&bytes[..]).unwrap(); + let block_header = BlockHeader::new(0); + let hash = block_header.merge_mining_hash(); + insert_merge_mining_tag_and_aux_chain_merkle_root_into_block(&mut block, hash, 1, 0).unwrap(); + + let coinbase = block.miner_tx.clone(); + let extra = coinbase.prefix.extra; + let mut keccak = Keccak::v256(); + let mut encoder_prefix = Vec::new(); + coinbase.prefix.version.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase + .prefix + .unlock_time + .consensus_encode(&mut encoder_prefix) + .unwrap(); + coinbase.prefix.inputs.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase.prefix.outputs.consensus_encode(&mut encoder_prefix).unwrap(); + keccak.update(&encoder_prefix); + + let mut finalised_prefix_keccak = keccak.clone(); + let mut encoder_extra_field = Vec::new(); + extra.consensus_encode(&mut encoder_extra_field).unwrap(); + finalised_prefix_keccak.update(&encoder_extra_field); + let mut prefix_hash: [u8; 32] = [0; 32]; + finalised_prefix_keccak.finalize(&mut prefix_hash); + + let test_prefix_hash = block.miner_tx.prefix.hash(); + let test2 = monero::Hash::from_slice(&prefix_hash); + assert_eq!(test_prefix_hash, test2); + + // let mut finalised_keccak = Keccak::v256(); + let rct_sig_base = RctSigBase { + rct_type: RctType::Null, + txn_fee: Default::default(), + pseudo_outs: vec![], + ecdh_info: vec![], + out_pk: vec![], + }; + let hashes = vec![test2, rct_sig_base.hash(), monero::Hash::null()]; + let encoder_final: Vec = hashes.into_iter().flat_map(|h| Vec::from(&h.to_bytes()[..])).collect(); + let coinbase = monero::Hash::new(encoder_final); + let coinbase_hash = block.miner_tx.hash(); + assert_eq!(coinbase, coinbase_hash); + } + #[test] fn test_monero_data() { let blocktemplate_blob = "0c0c8cd6a0fa057fe21d764e7abf004e975396a2160773b93712bf6118c3b4959ddd8ee0f76aad0000000002e1ea2701ffa5ea2701d5a299e2abb002028eb3066ced1b2cc82ea046f3716a48e9ae37144057d5fb48a97f941225a1957b2b0106225b7ec0a6544d8da39abe68d8bd82619b4a7c5bdae89c3783b256a8fa47820208f63aa86d2e857f070000".to_string(); let seed_hash = "9f02e032f9b15d2aded991e0f68cc3c3427270b568b782e55fbd269ead0bad97".to_string(); let bytes = hex::decode(blocktemplate_blob).unwrap(); + let rules = ConsensusManager::builder(Network::LocalNet).build().unwrap(); let mut block = deserialize::(&bytes[..]).unwrap(); let mut block_header = BlockHeader { version: 0, @@ -481,13 +566,28 @@ mod test { let aux_hashes = vec![monero::Hash::from_slice(hash.as_ref())]; let aux_chain_merkle_proof = create_merkle_proof(&aux_hashes, &aux_hashes[0]).unwrap(); + let coinbase = block.miner_tx.clone(); + let extra = coinbase.prefix.extra; + let mut keccak = Keccak::v256(); + let mut encoder_prefix = Vec::new(); + coinbase.prefix.version.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase + .prefix + .unlock_time + .consensus_encode(&mut encoder_prefix) + .unwrap(); + coinbase.prefix.inputs.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase.prefix.outputs.consensus_encode(&mut encoder_prefix).unwrap(); + keccak.update(&encoder_prefix); + let monero_data = MoneroPowData { header: block.header, randomx_key: FixedByteArray::from_canonical_bytes(&from_hex(&seed_hash).unwrap()).unwrap(), transaction_count: u16::try_from(hashes.len()).unwrap(), merkle_root: root, coinbase_merkle_proof, - coinbase_tx: block.miner_tx, + coinbase_tx_hasher: keccak.clone(), + coinbase_tx_extra: extra.clone(), aux_chain_merkle_proof, }; let mut serialized = Vec::new(); @@ -497,7 +597,33 @@ mod test { pow_data: serialized, }; block_header.pow = pow; - MoneroPowData::from_header(&block_header).unwrap(); + MoneroPowData::from_header(&block_header, &rules).unwrap(); + + // lets test the hashesh + let mut finalised_prefix_keccak = keccak.clone(); + let mut encoder_extra_field = Vec::new(); + extra.consensus_encode(&mut encoder_extra_field).unwrap(); + finalised_prefix_keccak.update(&encoder_extra_field); + let mut prefix_hash: [u8; 32] = [0; 32]; + finalised_prefix_keccak.finalize(&mut prefix_hash); + + let test_prefix_hash = block.miner_tx.prefix.hash(); + let test2 = monero::Hash::from_slice(&prefix_hash); + assert_eq!(test_prefix_hash, test2); + + // let mut finalised_keccak = Keccak::v256(); + let rct_sig_base = RctSigBase { + rct_type: RctType::Null, + txn_fee: Default::default(), + pseudo_outs: vec![], + ecdh_info: vec![], + out_pk: vec![], + }; + let hashes = vec![test2, rct_sig_base.hash(), monero::Hash::null()]; + let encoder_final: Vec = hashes.into_iter().flat_map(|h| Vec::from(&h.to_bytes()[..])).collect(); + let coinbase = monero::Hash::new(encoder_final); + let coinbase_hash = block.miner_tx.hash(); + assert_eq!(coinbase, coinbase_hash); } #[test] @@ -511,6 +637,7 @@ mod test { #[test] fn test_append_mm_tag() { + let rules = ConsensusManager::builder(Network::LocalNet).build().unwrap(); let blocktemplate_blob = "0c0c8cd6a0fa057fe21d764e7abf004e975396a2160773b93712bf6118c3b4959ddd8ee0f76aad0000000002e1ea2701ffa5ea2701d5a299e2abb002028eb3066ced1b2cc82ea046f3716a48e9ae37144057d5fb48a97f941225a1957b2b0106225b7ec0a6544d8da39abe68d8bd82619b4a7c5bdae89c3783b256a8fa47820208f63aa86d2e857f070000".to_string(); let seed_hash = "9f02e032f9b15d2aded991e0f68cc3c3427270b568b782e55fbd269ead0bad97".to_string(); let bytes = hex::decode(blocktemplate_blob).unwrap(); @@ -546,13 +673,29 @@ mod test { let coinbase_merkle_proof = create_merkle_proof(&hashes, &hashes[0]).unwrap(); let aux_hashes = vec![monero::Hash::from_slice(hash.as_ref())]; let aux_chain_merkle_proof = create_merkle_proof(&aux_hashes, &aux_hashes[0]).unwrap(); + + let coinbase = block.miner_tx.clone(); + let extra = coinbase.prefix.extra.clone(); + let mut keccak = Keccak::v256(); + let mut encoder_prefix = Vec::new(); + coinbase.prefix.version.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase + .prefix + .unlock_time + .consensus_encode(&mut encoder_prefix) + .unwrap(); + coinbase.prefix.inputs.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase.prefix.outputs.consensus_encode(&mut encoder_prefix).unwrap(); + keccak.update(&encoder_prefix); + let monero_data = MoneroPowData { header: block.header, randomx_key: FixedByteArray::from_canonical_bytes(&from_hex(&seed_hash).unwrap()).unwrap(), transaction_count: count, merkle_root: root, coinbase_merkle_proof, - coinbase_tx: block.miner_tx, + coinbase_tx_hasher: keccak, + coinbase_tx_extra: extra, aux_chain_merkle_proof, }; let mut serialized = Vec::new(); @@ -562,11 +705,13 @@ mod test { pow_data: serialized, }; block_header.pow = pow; - verify_header(&block_header, &hash).unwrap(); + + verify_header(&block_header, &hash, &rules).unwrap(); } #[test] fn test_append_mm_tag_no_tag() { + let rules = ConsensusManager::builder(Network::LocalNet).build().unwrap(); let blocktemplate_blob = "0c0c8cd6a0fa057fe21d764e7abf004e975396a2160773b93712bf6118c3b4959ddd8ee0f76aad0000000002e1ea2701ffa5ea2701d5a299e2abb002028eb3066ced1b2cc82ea046f3716a48e9ae37144057d5fb48a97f941225a1957b2b0106225b7ec0a6544d8da39abe68d8bd82619b4a7c5bdae89c3783b256a8fa47820208f63aa86d2e857f070000".to_string(); let seed_hash = "9f02e032f9b15d2aded991e0f68cc3c3427270b568b782e55fbd269ead0bad97".to_string(); let bytes = hex::decode(blocktemplate_blob).unwrap(); @@ -598,13 +743,29 @@ mod test { let coinbase_merkle_proof = create_merkle_proof(&hashes, &hashes[0]).unwrap(); let aux_hashes = vec![monero::Hash::from_slice(block_header.hash().as_ref())]; let aux_chain_merkle_proof = create_merkle_proof(&aux_hashes, &aux_hashes[0]).unwrap(); + + let coinbase = block.miner_tx.clone(); + let extra = coinbase.prefix.extra.clone(); + let mut keccak = Keccak::v256(); + let mut encoder_prefix = Vec::new(); + coinbase.prefix.version.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase + .prefix + .unlock_time + .consensus_encode(&mut encoder_prefix) + .unwrap(); + coinbase.prefix.inputs.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase.prefix.outputs.consensus_encode(&mut encoder_prefix).unwrap(); + keccak.update(&encoder_prefix); + let monero_data = MoneroPowData { header: block.header, randomx_key: FixedByteArray::from_canonical_bytes(&from_hex(&seed_hash).unwrap()).unwrap(), transaction_count: count, merkle_root: root, coinbase_merkle_proof, - coinbase_tx: block.miner_tx, + coinbase_tx_hasher: keccak, + coinbase_tx_extra: extra, aux_chain_merkle_proof, }; @@ -615,13 +776,14 @@ mod test { pow_data: serialized, }; block_header.pow = pow; - let err = verify_header(&block_header, &block_header.hash()).unwrap_err(); + let err = verify_header(&block_header, &block_header.hash(), &rules).unwrap_err(); unpack_enum!(MergeMineError::ValidationError(details) = err); assert!(details.contains("Expected merge mining tag was not found in Monero coinbase transaction")); } #[test] fn test_append_mm_tag_wrong_hash() { + let rules = ConsensusManager::builder(Network::LocalNet).build().unwrap(); let blocktemplate_blob = "0c0c8cd6a0fa057fe21d764e7abf004e975396a2160773b93712bf6118c3b4959ddd8ee0f76aad0000000002e1ea2701ffa5ea2701d5a299e2abb002028eb3066ced1b2cc82ea046f3716a48e9ae37144057d5fb48a97f941225a1957b2b0106225b7ec0a6544d8da39abe68d8bd82619b4a7c5bdae89c3783b256a8fa47820208f63aa86d2e857f070000".to_string(); let seed_hash = "9f02e032f9b15d2aded991e0f68cc3c3427270b568b782e55fbd269ead0bad97".to_string(); let bytes = hex::decode(blocktemplate_blob).unwrap(); @@ -658,13 +820,29 @@ mod test { let coinbase_merkle_proof = create_merkle_proof(&hashes, &hashes[0]).unwrap(); let aux_hashes = vec![monero::Hash::from_slice(hash.as_ref())]; let aux_chain_merkle_proof = create_merkle_proof(&aux_hashes, &aux_hashes[0]).unwrap(); + + let coinbase = block.miner_tx.clone(); + let extra = coinbase.prefix.extra.clone(); + let mut keccak = Keccak::v256(); + let mut encoder_prefix = Vec::new(); + coinbase.prefix.version.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase + .prefix + .unlock_time + .consensus_encode(&mut encoder_prefix) + .unwrap(); + coinbase.prefix.inputs.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase.prefix.outputs.consensus_encode(&mut encoder_prefix).unwrap(); + keccak.update(&encoder_prefix); + let monero_data = MoneroPowData { header: block.header, randomx_key: FixedByteArray::from_canonical_bytes(&from_hex(&seed_hash).unwrap()).unwrap(), transaction_count: count, merkle_root: root, coinbase_merkle_proof, - coinbase_tx: block.miner_tx, + coinbase_tx_hasher: keccak, + coinbase_tx_extra: extra, aux_chain_merkle_proof, }; let mut serialized = Vec::new(); @@ -674,13 +852,14 @@ mod test { pow_data: serialized, }; block_header.pow = pow; - let err = verify_header(&block_header, &block_header.hash()).unwrap_err(); + let err = verify_header(&block_header, &block_header.hash(), &rules).unwrap_err(); unpack_enum!(MergeMineError::ValidationError(details) = err); assert!(details.contains("Expected merge mining tag was not found in Monero coinbase transaction")); } #[test] fn test_duplicate_append_mm_tag() { + let rules = ConsensusManager::builder(Network::LocalNet).build().unwrap(); let blocktemplate_blob = "0c0c8cd6a0fa057fe21d764e7abf004e975396a2160773b93712bf6118c3b4959ddd8ee0f76aad0000000002e1ea2701ffa5ea2701d5a299e2abb002028eb3066ced1b2cc82ea046f3716a48e9ae37144057d5fb48a97f941225a1957b2b0106225b7ec0a6544d8da39abe68d8bd82619b4a7c5bdae89c3783b256a8fa47820208f63aa86d2e857f070000".to_string(); let seed_hash = "9f02e032f9b15d2aded991e0f68cc3c3427270b568b782e55fbd269ead0bad97".to_string(); let bytes = hex::decode(blocktemplate_blob).unwrap(); @@ -737,13 +916,29 @@ mod test { let coinbase_merkle_proof = create_merkle_proof(&hashes, &hashes[0]).unwrap(); let aux_hashes = vec![monero::Hash::from_slice(hash.as_ref())]; let aux_chain_merkle_proof = create_merkle_proof(&aux_hashes, &aux_hashes[0]).unwrap(); + + let coinbase = block.miner_tx.clone(); + let extra = coinbase.prefix.extra.clone(); + let mut keccak = Keccak::v256(); + let mut encoder_prefix = Vec::new(); + coinbase.prefix.version.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase + .prefix + .unlock_time + .consensus_encode(&mut encoder_prefix) + .unwrap(); + coinbase.prefix.inputs.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase.prefix.outputs.consensus_encode(&mut encoder_prefix).unwrap(); + keccak.update(&encoder_prefix); + let monero_data = MoneroPowData { header: block.header, randomx_key: FixedByteArray::from_canonical_bytes(&from_hex(&seed_hash).unwrap()).unwrap(), transaction_count: count, merkle_root: root, coinbase_merkle_proof, - coinbase_tx: block.miner_tx, + coinbase_tx_hasher: keccak, + coinbase_tx_extra: extra, aux_chain_merkle_proof, }; let mut serialized = Vec::new(); @@ -755,7 +950,7 @@ mod test { block_header.pow = pow; // Header verification will fail because there are more than one merge mining tag - let err = verify_header(&block_header, &block_header.hash()).unwrap_err(); + let err = verify_header(&block_header, &block_header.hash(), &rules).unwrap_err(); unpack_enum!(MergeMineError::ValidationError(details) = err); assert!(details.contains("More than one merge mining tag found in coinbase")); } @@ -820,6 +1015,7 @@ mod test { #[test] fn test_verify_header_no_coinbase() { + let rules = ConsensusManager::builder(Network::LocalNet).build().unwrap(); let blocktemplate_blob = "0c0c8cd6a0fa057fe21d764e7abf004e975396a2160773b93712bf6118c3b4959ddd8ee0f76aad0000000002e1ea2701ffa5ea2701d5a299e2abb002028eb3066ced1b2cc82ea046f3716a48e9ae37144057d5fb48a97f941225a1957b2b0106225b7ec0a6544d8da39abe68d8bd82619b4a7c5bdae89c3783b256a8fa47820208f63aa86d2e857f070000".to_string(); let seed_hash = "9f02e032f9b15d2aded991e0f68cc3c3427270b568b782e55fbd269ead0bad97".to_string(); let bytes = hex::decode(blocktemplate_blob).unwrap(); @@ -856,13 +1052,29 @@ mod test { let coinbase_merkle_proof = create_merkle_proof(&hashes, &hashes[0]).unwrap(); let aux_hashes = vec![monero::Hash::from_slice(hash.as_ref())]; let aux_chain_merkle_proof = create_merkle_proof(&aux_hashes, &aux_hashes[0]).unwrap(); + + let coinbase: monero::Transaction = Default::default(); + let extra = coinbase.prefix.extra.clone(); + let mut keccak = Keccak::v256(); + let mut encoder_prefix = Vec::new(); + coinbase.prefix.version.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase + .prefix + .unlock_time + .consensus_encode(&mut encoder_prefix) + .unwrap(); + coinbase.prefix.inputs.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase.prefix.outputs.consensus_encode(&mut encoder_prefix).unwrap(); + keccak.update(&encoder_prefix); + let monero_data = MoneroPowData { header: block.header, randomx_key: FixedByteArray::from_canonical_bytes(&from_hex(&seed_hash).unwrap()).unwrap(), transaction_count: count, merkle_root: root, coinbase_merkle_proof, - coinbase_tx: Default::default(), + coinbase_tx_hasher: keccak, + coinbase_tx_extra: extra, aux_chain_merkle_proof, }; let mut serialized = Vec::new(); @@ -872,13 +1084,14 @@ mod test { pow_data: serialized, }; block_header.pow = pow; - let err = verify_header(&block_header, &block_header.hash()).unwrap_err(); + let err = verify_header(&block_header, &block_header.hash(), &rules).unwrap_err(); unpack_enum!(MergeMineError::ValidationError(details) = err); assert!(details.contains("Expected merge mining tag was not found in Monero coinbase transaction")); } #[test] fn test_verify_header_no_data() { + let rules = ConsensusManager::builder(Network::LocalNet).build().unwrap(); let mut block_header = BlockHeader { version: 0, height: 0, @@ -896,6 +1109,20 @@ mod test { validator_node_mr: FixedHash::zero(), validator_node_size: 0, }; + let coinbase: monero::Transaction = Default::default(); + + let extra = coinbase.prefix.extra.clone(); + let mut keccak = Keccak::v256(); + let mut encoder_prefix = Vec::new(); + coinbase.prefix.version.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase + .prefix + .unlock_time + .consensus_encode(&mut encoder_prefix) + .unwrap(); + coinbase.prefix.inputs.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase.prefix.outputs.consensus_encode(&mut encoder_prefix).unwrap(); + keccak.update(&encoder_prefix); let monero_data = MoneroPowData { header: Default::default(), @@ -903,7 +1130,8 @@ mod test { transaction_count: 1, merkle_root: Default::default(), coinbase_merkle_proof: create_merkle_proof(&[Hash::null()], &Hash::null()).unwrap(), - coinbase_tx: Default::default(), + coinbase_tx_hasher: keccak, + coinbase_tx_extra: extra, aux_chain_merkle_proof: Default::default(), }; let mut serialized = Vec::new(); @@ -913,13 +1141,14 @@ mod test { pow_data: serialized, }; block_header.pow = pow; - let err = verify_header(&block_header, &block_header.hash()).unwrap_err(); + let err = verify_header(&block_header, &block_header.hash(), &rules).unwrap_err(); unpack_enum!(MergeMineError::ValidationError(details) = err); assert!(details.contains("Expected merge mining tag was not found in Monero coinbase transaction")); } #[test] fn test_verify_invalid_root() { + let rules = ConsensusManager::builder(Network::LocalNet).build().unwrap(); let blocktemplate_blob = "0c0c8cd6a0fa057fe21d764e7abf004e975396a2160773b93712bf6118c3b4959ddd8ee0f76aad0000000002e1ea2701ffa5ea2701d5a299e2abb002028eb3066ced1b2cc82ea046f3716a48e9ae37144057d5fb48a97f941225a1957b2b0106225b7ec0a6544d8da39abe68d8bd82619b4a7c5bdae89c3783b256a8fa47820208f63aa86d2e857f070000".to_string(); let seed_hash = "9f02e032f9b15d2aded991e0f68cc3c3427270b568b782e55fbd269ead0bad97".to_string(); let bytes = hex::decode(blocktemplate_blob).unwrap(); @@ -956,13 +1185,29 @@ mod test { let coinbase_merkle_proof = create_merkle_proof(&hashes, &hashes[0]).unwrap(); let aux_hashes = vec![monero::Hash::from_slice(hash.as_ref())]; let aux_chain_merkle_proof = create_merkle_proof(&aux_hashes, &aux_hashes[0]).unwrap(); + + let coinbase = block.miner_tx.clone(); + let extra = coinbase.prefix.extra.clone(); + let mut keccak = Keccak::v256(); + let mut encoder_prefix = Vec::new(); + coinbase.prefix.version.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase + .prefix + .unlock_time + .consensus_encode(&mut encoder_prefix) + .unwrap(); + coinbase.prefix.inputs.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase.prefix.outputs.consensus_encode(&mut encoder_prefix).unwrap(); + keccak.update(&encoder_prefix); + let monero_data = MoneroPowData { header: block.header, randomx_key: FixedByteArray::from_canonical_bytes(&from_hex(&seed_hash).unwrap()).unwrap(), transaction_count: count, merkle_root: Hash::null(), coinbase_merkle_proof, - coinbase_tx: block.miner_tx, + coinbase_tx_hasher: keccak, + coinbase_tx_extra: extra, aux_chain_merkle_proof, }; let mut serialized = Vec::new(); @@ -972,7 +1217,7 @@ mod test { pow_data: serialized, }; block_header.pow = pow; - let err = verify_header(&block_header, &block_header.hash()).unwrap_err(); + let err = verify_header(&block_header, &block_header.hash(), &rules).unwrap_err(); unpack_enum!(MergeMineError::InvalidMerkleRoot = err); } diff --git a/base_layer/core/src/proof_of_work/monero_rx/pow_data.rs b/base_layer/core/src/proof_of_work/monero_rx/pow_data.rs index d339d40aaa..7cd30f883b 100644 --- a/base_layer/core/src/proof_of_work/monero_rx/pow_data.rs +++ b/base_layer/core/src/proof_of_work/monero_rx/pow_data.rs @@ -29,13 +29,20 @@ use std::{ use borsh::{BorshDeserialize, BorshSerialize}; use monero::{ + blockdata::transaction::RawExtraField, consensus::{Decodable, Encodable}, cryptonote::hash::Hashable, + util::ringct::{RctSigBase, RctType}, }; use tari_utilities::hex::{to_hex, Hex}; +use tiny_keccak::{Hasher, Keccak}; use super::{error::MergeMineError, fixed_array::FixedByteArray, merkle_tree::MerkleProof}; -use crate::{blocks::BlockHeader, proof_of_work::monero_rx::helpers::create_block_hashing_blob}; +use crate::{ + blocks::BlockHeader, + consensus::ConsensusManager, + proof_of_work::monero_rx::helpers::create_block_hashing_blob, +}; /// This is a struct to deserialize the data from he pow field into data required for the randomX Monero merged mine /// pow. @@ -52,8 +59,10 @@ pub struct MoneroPowData { pub merkle_root: monero::Hash, /// Coinbase merkle proof hashes pub coinbase_merkle_proof: MerkleProof, - /// Coinbase tx from Monero - pub coinbase_tx: monero::Transaction, + /// incomplete hashed state of the coinbase transaction + pub coinbase_tx_hasher: Keccak, + /// extra field of the coinbase + pub coinbase_tx_extra: RawExtraField, /// aux chain merkle proof hashes pub aux_chain_merkle_proof: MerkleProof, } @@ -65,7 +74,8 @@ impl BorshSerialize for MoneroPowData { BorshSerialize::serialize(&self.transaction_count, writer)?; self.merkle_root.consensus_encode(writer)?; BorshSerialize::serialize(&self.coinbase_merkle_proof, writer)?; - self.coinbase_tx.consensus_encode(writer)?; + BorshSerialize::serialize(&self.coinbase_tx_hasher, writer)?; + BorshSerialize::serialize(&self.coinbase_tx_extra.0, writer)?; BorshSerialize::serialize(&self.aux_chain_merkle_proof, writer)?; Ok(()) } @@ -81,8 +91,8 @@ impl BorshDeserialize for MoneroPowData { let merkle_root = monero::Hash::consensus_decode(reader) .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e.to_string()))?; let coinbase_merkle_proof = BorshDeserialize::deserialize_reader(reader)?; - let coinbase_tx = monero::Transaction::consensus_decode(reader) - .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e.to_string()))?; + let coinbase_tx_hasher = BorshDeserialize::deserialize_reader(reader)?; + let coinbase_tx_extra = RawExtraField(BorshDeserialize::deserialize_reader(reader)?); let aux_chain_merkle_proof = BorshDeserialize::deserialize_reader(reader)?; Ok(Self { header, @@ -90,7 +100,8 @@ impl BorshDeserialize for MoneroPowData { transaction_count, merkle_root, coinbase_merkle_proof, - coinbase_tx, + coinbase_tx_hasher, + coinbase_tx_extra, aux_chain_merkle_proof, }) } @@ -98,10 +109,21 @@ impl BorshDeserialize for MoneroPowData { impl MoneroPowData { /// Create a new MoneroPowData struct from the given header - pub fn from_header(tari_header: &BlockHeader) -> Result { + pub fn from_header( + tari_header: &BlockHeader, + consensus: &ConsensusManager, + ) -> Result { let mut v = tari_header.pow.pow_data.as_slice(); - let pow_data = + let pow_data: MoneroPowData = BorshDeserialize::deserialize(&mut v).map_err(|e| MergeMineError::DeserializeError(format!("{:?}", e)))?; + if pow_data.coinbase_tx_extra.0.len() > consensus.consensus_constants(tari_header.height).max_extra_field_size() + { + return Err(MergeMineError::DeserializeError(format!( + "Extra size({}) is larger than allowed {} bytes", + pow_data.coinbase_tx_extra.0.len(), + consensus.consensus_constants(tari_header.height).max_extra_field_size() + ))); + } if !v.is_empty() { return Err(MergeMineError::DeserializeError(format!( "{} bytes leftover after deserialize", @@ -128,7 +150,29 @@ impl MoneroPowData { /// Returns true if the coinbase merkle proof produces the `merkle_root` hash, otherwise false pub fn is_coinbase_valid_merkle_root(&self) -> bool { - let coinbase_hash = self.coinbase_tx.hash(); + let mut finalised_prefix_keccak = self.coinbase_tx_hasher.clone(); + let mut encoder_extra_field = Vec::new(); + self.coinbase_tx_extra + .consensus_encode(&mut encoder_extra_field) + .unwrap(); + finalised_prefix_keccak.update(&encoder_extra_field); + let mut prefix_hash: [u8; 32] = [0; 32]; + finalised_prefix_keccak.finalize(&mut prefix_hash); + + let final_prefix_hash = monero::Hash::from_slice(&prefix_hash); + + // let mut finalised_keccak = Keccak::v256(); + let rct_sig_base = RctSigBase { + rct_type: RctType::Null, + txn_fee: Default::default(), + pseudo_outs: vec![], + ecdh_info: vec![], + out_pk: vec![], + }; + let hashes = vec![final_prefix_hash, rct_sig_base.hash(), monero::Hash::null()]; + let encoder_final: Vec = hashes.into_iter().flat_map(|h| Vec::from(&h.to_bytes()[..])).collect(); + let coinbase_hash = monero::Hash::new(encoder_final); + let merkle_root = self.coinbase_merkle_proof.calculate_root(&coinbase_hash); (self.merkle_root == merkle_root) && self.coinbase_merkle_proof.check_coinbase_path() } @@ -149,22 +193,36 @@ impl Display for MoneroPowData { writeln!(fmt, "MoneroBlockHeader: {} ", self.header)?; writeln!(fmt, "RandomX vm key: {}", self.randomx_key.to_hex())?; writeln!(fmt, "Monero tx count: {}", self.transaction_count)?; - writeln!(fmt, "Monero tx root: {}", to_hex(self.merkle_root.as_bytes()))?; - writeln!(fmt, "Monero coinbase tx: {}", self.coinbase_tx) + writeln!(fmt, "Monero tx root: {}", to_hex(self.merkle_root.as_bytes())) } } #[cfg(test)] mod test { use borsh::{BorshDeserialize, BorshSerialize}; - use monero::{BlockHeader, Hash, Transaction, VarInt}; + use monero::{consensus::Encodable, BlockHeader, Hash, VarInt}; use tari_utilities::ByteArray; + use tiny_keccak::{Hasher, Keccak}; use super::MoneroPowData; use crate::proof_of_work::monero_rx::{merkle_tree::MerkleProof, FixedByteArray}; #[test] fn test_borsh_de_serialization() { + let coinbase: monero::Transaction = Default::default(); + let extra = coinbase.prefix.extra.clone(); + let mut keccak = Keccak::v256(); + let mut encoder_prefix = Vec::new(); + coinbase.prefix.version.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase + .prefix + .unlock_time + .consensus_encode(&mut encoder_prefix) + .unwrap(); + coinbase.prefix.inputs.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase.prefix.outputs.consensus_encode(&mut encoder_prefix).unwrap(); + keccak.update(&encoder_prefix); + let monero_pow_data = MoneroPowData { header: BlockHeader { major_version: VarInt(1), @@ -177,7 +235,8 @@ mod test { transaction_count: 9, merkle_root: Hash::new([10; 32]), coinbase_merkle_proof: MerkleProof::default(), - coinbase_tx: Transaction::default(), + coinbase_tx_extra: extra, + coinbase_tx_hasher: keccak, aux_chain_merkle_proof: MerkleProof::default(), }; let mut buf = Vec::new(); diff --git a/base_layer/core/src/proof_of_work/proof_of_work.rs b/base_layer/core/src/proof_of_work/proof_of_work.rs index c3cbe1c107..036a9be61e 100644 --- a/base_layer/core/src/proof_of_work/proof_of_work.rs +++ b/base_layer/core/src/proof_of_work/proof_of_work.rs @@ -33,7 +33,6 @@ pub trait AchievedDifficulty {} /// The proof of work data structure that is included in the block header. There's some non-Rustlike redundancy here /// to make serialization more straightforward -#[allow(deprecated)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct ProofOfWork { /// The algorithm used to mine this block @@ -44,7 +43,6 @@ pub struct ProofOfWork { } impl Default for ProofOfWork { - #[allow(deprecated)] fn default() -> Self { Self { pow_algo: PowAlgorithm::Sha3x, diff --git a/base_layer/core/src/proof_of_work/proof_of_work_algorithm.rs b/base_layer/core/src/proof_of_work/proof_of_work_algorithm.rs index fa74c79f3e..af66333cfd 100644 --- a/base_layer/core/src/proof_of_work/proof_of_work_algorithm.rs +++ b/base_layer/core/src/proof_of_work/proof_of_work_algorithm.rs @@ -32,6 +32,7 @@ use thiserror::Error; /// Indicates the algorithm used to mine a block #[repr(u8)] #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Hash, Eq, BorshSerialize, BorshDeserialize)] +#[borsh(use_discriminant = true)] pub enum PowAlgorithm { RandomX = 0, Sha3x = 1, diff --git a/base_layer/core/src/transactions/aggregated_body.rs b/base_layer/core/src/transactions/aggregated_body.rs index 5602f2d7a0..69b7a75887 100644 --- a/base_layer/core/src/transactions/aggregated_body.rs +++ b/base_layer/core/src/transactions/aggregated_body.rs @@ -53,7 +53,7 @@ pub const LOG_TARGET: &str = "c::tx::aggregated_body"; pub struct AggregateBody { /// This flag indicates if the inputs, outputs and kernels have been sorted internally, that is, the sort() method /// has been called. This may be false even if all components are sorted. - #[borsh_skip] + #[borsh(skip)] sorted: bool, /// List of inputs spent by the transaction. inputs: Vec, diff --git a/base_layer/core/src/transactions/transaction_components/output_features_version.rs b/base_layer/core/src/transactions/transaction_components/output_features_version.rs index 221bfe208c..ef6b760ec9 100644 --- a/base_layer/core/src/transactions/transaction_components/output_features_version.rs +++ b/base_layer/core/src/transactions/transaction_components/output_features_version.rs @@ -22,6 +22,7 @@ use strum_macros::Display; BorshDeserialize, )] #[repr(u8)] +#[borsh(use_discriminant = true)] pub enum OutputFeaturesVersion { V0 = 0, V1 = 1, diff --git a/base_layer/core/src/transactions/transaction_components/output_type.rs b/base_layer/core/src/transactions/transaction_components/output_type.rs index 9eb15402ed..8c0a2ff589 100644 --- a/base_layer/core/src/transactions/transaction_components/output_type.rs +++ b/base_layer/core/src/transactions/transaction_components/output_type.rs @@ -44,6 +44,7 @@ use serde_repr::{Deserialize_repr, Serialize_repr}; BorshDeserialize, )] #[repr(u8)] +#[borsh(use_discriminant = true)] pub enum OutputType { /// An standard output. Standard = 0, diff --git a/base_layer/core/src/transactions/transaction_components/range_proof_type.rs b/base_layer/core/src/transactions/transaction_components/range_proof_type.rs index bce0b07554..1d9e88d9ad 100644 --- a/base_layer/core/src/transactions/transaction_components/range_proof_type.rs +++ b/base_layer/core/src/transactions/transaction_components/range_proof_type.rs @@ -36,6 +36,7 @@ use serde::{Deserialize, Serialize}; )] #[repr(u8)] #[serde(rename_all = "snake_case")] +#[borsh(use_discriminant = true)] pub enum RangeProofType { /// Range proof is a BulletProofPlus BulletProofPlus = 0, diff --git a/base_layer/core/src/transactions/transaction_components/test.rs b/base_layer/core/src/transactions/transaction_components/test.rs index 80196e3188..d68ca986a7 100644 --- a/base_layer/core/src/transactions/transaction_components/test.rs +++ b/base_layer/core/src/transactions/transaction_components/test.rs @@ -534,7 +534,6 @@ async fn test_output_recover_openings() { mod validate_internal_consistency { use blake2::Blake2b; - use borsh::BorshSerialize; use digest::{consts::U32, Digest}; use tari_common_types::types::FixedHash; use tari_crypto::hashing::DomainSeparation; @@ -608,7 +607,10 @@ mod validate_internal_consistency { let mut hasher = Blake2b::::default(); BaseLayerCovenantsDomain::add_domain_separation_tag(&mut hasher, COVENANTS_FIELD_HASHER_LABEL); - let hash = hasher.chain_update(features.try_to_vec().unwrap()).finalize().to_vec(); + let hash = hasher + .chain_update(borsh::to_vec(&features).unwrap()) + .finalize() + .to_vec(); let mut slice = [0u8; FixedHash::byte_size()]; slice.copy_from_slice(hash.as_ref()); diff --git a/base_layer/core/src/transactions/transaction_components/transaction_input_version.rs b/base_layer/core/src/transactions/transaction_components/transaction_input_version.rs index f0bbc21038..8bf326b0e7 100644 --- a/base_layer/core/src/transactions/transaction_components/transaction_input_version.rs +++ b/base_layer/core/src/transactions/transaction_components/transaction_input_version.rs @@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, PartialOrd, BorshSerialize, BorshDeserialize)] #[repr(u8)] +#[borsh(use_discriminant = true)] pub enum TransactionInputVersion { V0 = 0, /// Currently only used in tests, this can be used as the next version diff --git a/base_layer/core/src/transactions/transaction_components/transaction_kernel_version.rs b/base_layer/core/src/transactions/transaction_components/transaction_kernel_version.rs index db7aa7b14e..c31ed4bc79 100644 --- a/base_layer/core/src/transactions/transaction_components/transaction_kernel_version.rs +++ b/base_layer/core/src/transactions/transaction_components/transaction_kernel_version.rs @@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, PartialOrd, BorshSerialize, BorshDeserialize)] #[repr(u8)] +#[borsh(use_discriminant = true)] pub enum TransactionKernelVersion { V0 = 0, } diff --git a/base_layer/core/src/transactions/transaction_components/transaction_output_version.rs b/base_layer/core/src/transactions/transaction_components/transaction_output_version.rs index 89fdd50bf1..405700a72c 100644 --- a/base_layer/core/src/transactions/transaction_components/transaction_output_version.rs +++ b/base_layer/core/src/transactions/transaction_components/transaction_output_version.rs @@ -30,6 +30,7 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, PartialOrd, BorshSerialize, BorshDeserialize)] #[repr(u8)] +#[borsh(use_discriminant = true)] pub enum TransactionOutputVersion { V0 = 0, /// Currently only used in tests, this can be used as the next version diff --git a/base_layer/core/src/validation/difficulty_calculator.rs b/base_layer/core/src/validation/difficulty_calculator.rs index 6bdf7435a7..57356825ed 100644 --- a/base_layer/core/src/validation/difficulty_calculator.rs +++ b/base_layer/core/src/validation/difficulty_calculator.rs @@ -52,7 +52,8 @@ impl DifficultyCalculator { constants.max_pow_difficulty(block_header.pow.pow_algo), ); let gen_hash = *self.rules.get_genesis_block().hash(); - let achieved_target = check_target_difficulty(block_header, target, &self.randomx_factory, &gen_hash)?; + let achieved_target = + check_target_difficulty(block_header, target, &self.randomx_factory, &gen_hash, &self.rules)?; Ok(achieved_target) } diff --git a/base_layer/core/src/validation/header/header_full_validator.rs b/base_layer/core/src/validation/header/header_full_validator.rs index 3f99583b15..0adbe89107 100644 --- a/base_layer/core/src/validation/header/header_full_validator.rs +++ b/base_layer/core/src/validation/header/header_full_validator.rs @@ -80,7 +80,13 @@ impl HeaderChainLinkedValidator for HeaderFullValidator let gen_hash = *self.rules.get_genesis_block().hash(); let achieved_target = if let Some(target) = target_difficulty { - check_target_difficulty(header, target, &self.difficulty_calculator.randomx_factory, &gen_hash)? + check_target_difficulty( + header, + target, + &self.difficulty_calculator.randomx_factory, + &gen_hash, + &self.rules, + )? } else { self.difficulty_calculator .check_achieved_and_target_difficulty(db, header)? @@ -188,7 +194,7 @@ fn check_pow_data( BlockHeaderValidationError::InvalidNonce, )); } - let monero_data = MoneroPowData::from_header(block_header)?; + let monero_data = MoneroPowData::from_header(block_header, rules)?; let seed_height = db.fetch_monero_seed_first_seen_height(&monero_data.randomx_key)?; if seed_height != 0 { // Saturating sub: subtraction can underflow in reorgs / rewind-blockchain command diff --git a/base_layer/core/src/validation/helpers.rs b/base_layer/core/src/validation/helpers.rs index 2df8a469a8..cc6706fa5d 100644 --- a/base_layer/core/src/validation/helpers.rs +++ b/base_layer/core/src/validation/helpers.rs @@ -31,7 +31,7 @@ use crate::{ blocks::{BlockHeader, BlockHeaderValidationError, BlockValidationError}, borsh::SerializedSize, chain_storage::{BlockchainBackend, MmrRoots, MmrTree}, - consensus::ConsensusConstants, + consensus::{ConsensusConstants, ConsensusManager}, covenants::Covenant, proof_of_work::{ randomx_difficulty, @@ -121,9 +121,10 @@ pub fn check_target_difficulty( target: Difficulty, randomx_factory: &RandomXFactory, gen_hash: &FixedHash, + consensus: &ConsensusManager, ) -> Result { let achieved = match block_header.pow_algo() { - PowAlgorithm::RandomX => randomx_difficulty(block_header, randomx_factory, gen_hash)?, + PowAlgorithm::RandomX => randomx_difficulty(block_header, randomx_factory, gen_hash, consensus)?, PowAlgorithm::Sha3x => sha3x_difficulty(block_header)?, }; diff --git a/base_layer/core/tests/tests/block_validation.rs b/base_layer/core/tests/tests/block_validation.rs index 013512c73b..891c1d57bd 100644 --- a/base_layer/core/tests/tests/block_validation.rs +++ b/base_layer/core/tests/tests/block_validation.rs @@ -23,7 +23,7 @@ use std::{iter, sync::Arc}; use borsh::BorshSerialize; -use monero::blockdata::block::Block as MoneroBlock; +use monero::{blockdata::block::Block as MoneroBlock, consensus::Encodable}; use rand::{rngs::OsRng, RngCore}; use tari_common::configuration::Network; use tari_common_types::types::FixedHash; @@ -75,6 +75,7 @@ use tari_key_manager::key_manager_service::KeyManagerInterface; use tari_script::{inputs, script}; use tari_test_utils::unpack_enum; use tari_utilities::{epoch_time::EpochTime, hex::Hex}; +use tiny_keccak::{Hasher, Keccak}; use tokio::time::Instant; use crate::{ @@ -176,7 +177,7 @@ async fn test_monero_blocks() { block_3.header.nonce = 1; let hash2 = block_3.hash(); assert_ne!(hash1, hash2); - assert!(verify_header(&block_3.header, &gen_hash).is_ok()); + assert!(verify_header(&block_3.header, &gen_hash, &cm).is_ok()); match db.add_block(Arc::new(block_3.clone())) { Err(ChainStorageError::ValidationError { source: ValidationError::BlockHeaderError(BlockHeaderValidationError::InvalidNonce), @@ -206,6 +207,21 @@ fn add_monero_data(tblock: &mut Block, seed_key: &str) { let coinbase_merkle_proof = monero_rx::create_merkle_proof(&hashes, &hashes[0]).unwrap(); let aux_hashes = vec![hash]; let aux_chain_merkle_proof = monero_rx::create_merkle_proof(&aux_hashes, &aux_hashes[0]).unwrap(); + + let coinbase = mblock.miner_tx.clone(); + let extra = coinbase.prefix.extra.clone(); + let mut keccak = Keccak::v256(); + let mut encoder_prefix = Vec::new(); + coinbase.prefix.version.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase + .prefix + .unlock_time + .consensus_encode(&mut encoder_prefix) + .unwrap(); + coinbase.prefix.inputs.consensus_encode(&mut encoder_prefix).unwrap(); + coinbase.prefix.outputs.consensus_encode(&mut encoder_prefix).unwrap(); + keccak.update(&encoder_prefix); + #[allow(clippy::cast_possible_truncation)] let monero_data = MoneroPowData { header: mblock.header, @@ -213,7 +229,8 @@ fn add_monero_data(tblock: &mut Block, seed_key: &str) { transaction_count: hashes.len() as u16, merkle_root, coinbase_merkle_proof, - coinbase_tx: mblock.miner_tx, + coinbase_tx_extra: extra, + coinbase_tx_hasher: keccak, aux_chain_merkle_proof, }; let mut serialized = Vec::new(); diff --git a/base_layer/key_manager/Cargo.toml b/base_layer/key_manager/Cargo.toml index 035e36fa1f..fbdcca2390 100644 --- a/base_layer/key_manager/Cargo.toml +++ b/base_layer/key_manager/Cargo.toml @@ -11,7 +11,7 @@ edition = "2021" crate-type = ["lib", "cdylib"] [dependencies] -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } tari_utilities = { version = "0.6" } tari_common_sqlite = { path = "../../common_sqlite" } tari_common_types = { path = "../../base_layer/common_types"} diff --git a/base_layer/mmr/Cargo.toml b/base_layer/mmr/Cargo.toml index 863a3618b9..206eca4013 100644 --- a/base_layer/mmr/Cargo.toml +++ b/base_layer/mmr/Cargo.toml @@ -12,10 +12,10 @@ default = [] [dependencies] tari_utilities = { version = "0.6" } -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } tari_common = { path = "../../common" } thiserror = "1.0" -borsh = "0.10" +borsh = "1.2" digest = "0.10" log = "0.4" serde = { version = "1.0", features = ["derive"] } diff --git a/base_layer/p2p/Cargo.toml b/base_layer/p2p/Cargo.toml index ce6a291dda..9fd5413f31 100644 --- a/base_layer/p2p/Cargo.toml +++ b/base_layer/p2p/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" tari_comms = { path = "../../comms/core" } tari_comms_dht = { path = "../../comms/dht" } tari_common = { path = "../../common" } -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } tari_service_framework = { path = "../service_framework" } tari_shutdown = { path = "../../infrastructure/shutdown" } tari_storage = { path = "../../infrastructure/storage" } diff --git a/base_layer/tari_mining_helper_ffi/Cargo.toml b/base_layer/tari_mining_helper_ffi/Cargo.toml index f7836d8d36..43131abd1a 100644 --- a/base_layer/tari_mining_helper_ffi/Cargo.toml +++ b/base_layer/tari_mining_helper_ffi/Cargo.toml @@ -8,13 +8,13 @@ edition = "2018" [dependencies] tari_comms = { path = "../../comms/core" } -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } tari_common = { path = "../../common" } tari_core = { path = "../core", default-features = false, features = ["transactions"]} tari_utilities = { version = "0.6" } libc = "0.2.65" thiserror = "1.0.26" -borsh = "0.10" +borsh = "1.2" hex = "0.4.2" [dev-dependencies] diff --git a/base_layer/tari_mining_helper_ffi/src/lib.rs b/base_layer/tari_mining_helper_ffi/src/lib.rs index 006f3f3e9f..4b22d13f45 100644 --- a/base_layer/tari_mining_helper_ffi/src/lib.rs +++ b/base_layer/tari_mining_helper_ffi/src/lib.rs @@ -392,7 +392,7 @@ mod tests { let mut error = -1; let error_ptr = &mut error as *mut c_int; let block = create_test_block(); - let header_bytes = block.header.try_to_vec().unwrap(); + let header_bytes = borsh::to_vec(&block.header).unwrap(); #[allow(clippy::cast_possible_truncation)] let len = header_bytes.len() as u32; let byte_vec = byte_vector_create(header_bytes.as_ptr(), len, error_ptr); @@ -421,7 +421,7 @@ mod tests { let mut error = -1; let error_ptr = &mut error as *mut c_int; let block = create_test_block(); - let header_bytes = block.header.try_to_vec().unwrap(); + let header_bytes = borsh::to_vec(&block.header).unwrap(); let len = u32::try_from(header_bytes.len()).unwrap(); let byte_vec = byte_vector_create(header_bytes.as_ptr(), len, error_ptr); inject_nonce(byte_vec, nonce, error_ptr); @@ -438,7 +438,7 @@ mod tests { let mut error = -1; let error_ptr = &mut error as *mut c_int; let block = create_test_block(); - let header_bytes = block.header.try_to_vec().unwrap(); + let header_bytes = borsh::to_vec(&block.header).unwrap(); #[allow(clippy::cast_possible_truncation)] let len = header_bytes.len() as u32; let byte_vec = byte_vector_create(header_bytes.as_ptr(), len, error_ptr); @@ -461,7 +461,7 @@ mod tests { let hash_hex_broken_ptr: *const c_char = CString::into_raw(hash_hex_broken) as *const c_char; let mut template_difficulty = 30000; let mut share_difficulty = 24000; - let header_bytes = block.header.try_to_vec().unwrap(); + let header_bytes = borsh::to_vec(&block.header).unwrap(); #[allow(clippy::cast_possible_truncation)] let len = header_bytes.len() as u32; let byte_vec = byte_vector_create(header_bytes.as_ptr(), len, error_ptr); diff --git a/base_layer/wallet/Cargo.toml b/base_layer/wallet/Cargo.toml index 1f80024d19..2b83c33659 100644 --- a/base_layer/wallet/Cargo.toml +++ b/base_layer/wallet/Cargo.toml @@ -12,7 +12,7 @@ tari_common = { path = "../../common" } tari_common_types = { path = "../../base_layer/common_types" } tari_comms = { path = "../../comms/core" } tari_comms_dht = { path = "../../comms/dht" } -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } tari_key_manager = { path = "../key_manager", features = ["key_manager_service"] } tari_p2p = { path = "../p2p", features = ["auto-update"] } tari_script = { path = "../../infrastructure/tari_script" } @@ -32,7 +32,7 @@ async-trait = "0.1.50" argon2 = "0.4.1" bincode = "1.3.1" blake2 = "0.10" -borsh = "0.10" +borsh = "1.2" sha2 = "0.10" chrono = { version = "0.4.19", default-features = false, features = ["serde"] } derivative = "2.2.0" diff --git a/base_layer/wallet_ffi/Cargo.toml b/base_layer/wallet_ffi/Cargo.toml index 832193aae8..b46269f73a 100644 --- a/base_layer/wallet_ffi/Cargo.toml +++ b/base_layer/wallet_ffi/Cargo.toml @@ -12,7 +12,7 @@ tari_common = { path="../../common" } tari_common_types = { path="../common_types" } tari_comms = { path = "../../comms/core", features = ["c_integration"]} tari_comms_dht = { path = "../../comms/dht", default-features = false } -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } tari_key_manager = { path = "../key_manager" } tari_p2p = { path = "../p2p" } tari_script = { path = "../../infrastructure/tari_script" } @@ -48,7 +48,7 @@ tari_key_manager = { path = "../key_manager" } tari_common_types = { path = "../../base_layer/common_types"} tari_test_utils = { path = "../../infrastructure/test_utils"} tari_service_framework = { path = "../../base_layer/service_framework" } -borsh = "0.10" +borsh = "1.2" [build-dependencies] cbindgen = "0.24.3" diff --git a/base_layer/wallet_ffi/src/lib.rs b/base_layer/wallet_ffi/src/lib.rs index 78cb2065ad..95608462ce 100644 --- a/base_layer/wallet_ffi/src/lib.rs +++ b/base_layer/wallet_ffi/src/lib.rs @@ -8567,7 +8567,6 @@ mod test { sync::Mutex, }; - use borsh::BorshSerialize; use libc::{c_char, c_uchar, c_uint}; use minotari_wallet::{ storage::sqlite_utilities::run_migration_and_create_sqlite_connection, @@ -9104,7 +9103,7 @@ mod test { let error_ptr = &mut error as *mut c_int; let expected_covenant = covenant!(identity()); - let covenant_bytes = Box::into_raw(Box::new(ByteVector(expected_covenant.try_to_vec().unwrap()))); + let covenant_bytes = Box::into_raw(Box::new(ByteVector(borsh::to_vec(&expected_covenant).unwrap()))); let covenant = covenant_create_from_bytes(covenant_bytes, error_ptr); assert_eq!(error, 0); diff --git a/common/Cargo.toml b/common/Cargo.toml index fe0007b69a..daad9791f0 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -14,7 +14,7 @@ build = ["toml", "prost-build"] static-application-info = ["git2"] [dependencies] -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } anyhow = "1.0.53" blake2 = "0.10" diff --git a/comms/core/Cargo.toml b/comms/core/Cargo.toml index 390cd0a5ad..0b294b6ee2 100644 --- a/comms/core/Cargo.toml +++ b/comms/core/Cargo.toml @@ -10,7 +10,7 @@ version = "0.53.0-pre.0" edition = "2018" [dependencies] -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } tari_metrics = { path = "../../infrastructure/metrics", optional = true } tari_storage = { path = "../../infrastructure/storage" } tari_shutdown = { path = "../../infrastructure/shutdown" } diff --git a/comms/dht/Cargo.toml b/comms/dht/Cargo.toml index f405b1105e..18c0989854 100644 --- a/comms/dht/Cargo.toml +++ b/comms/dht/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" tari_comms = { path = "../core", features = ["rpc"] } tari_common = { path = "../../common" } tari_comms_rpc_macros = { path = "../rpc_macros" } -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } tari_utilities = { version = "0.6" } tari_shutdown = { path = "../../infrastructure/shutdown" } tari_storage = { path = "../../infrastructure/storage" } diff --git a/infrastructure/tari_script/Cargo.toml b/infrastructure/tari_script/Cargo.toml index 4861580912..0799e8e656 100644 --- a/infrastructure/tari_script/Cargo.toml +++ b/infrastructure/tari_script/Cargo.toml @@ -11,11 +11,11 @@ readme = "README.md" license = "BSD-3-Clause" [dependencies] -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } tari_utilities = { version = "0.6" } blake2 = "0.10" -borsh = "0.10" +borsh = "1.2" digest = "0.10" integer-encoding = "3.0.2" serde = "1.0.136" diff --git a/integration_tests/Cargo.toml b/integration_tests/Cargo.toml index 965e3c9e18..673c2aa1eb 100644 --- a/integration_tests/Cargo.toml +++ b/integration_tests/Cargo.toml @@ -13,7 +13,7 @@ minotari_node = { path = "../applications/minotari_node" } minotari_node_grpc_client = { path = "../clients/rust/base_node_grpc_client" } tari_chat_client = { path = "../base_layer/contacts/src/chat_client" } minotari_chat_ffi = { path = "../base_layer/chat_ffi" } -tari_crypto = { version = "0.19" } +tari_crypto = { version = "0.19.1" } tari_common = { path = "../common" } tari_common_types = { path = "../base_layer/common_types" } tari_comms = { path = "../comms/core" } diff --git a/integration_tests/tests/features/WalletFFI.feature b/integration_tests/tests/features/WalletFFI.feature index c92edbf34d..8a820f6268 100644 --- a/integration_tests/tests/features/WalletFFI.feature +++ b/integration_tests/tests/features/WalletFFI.feature @@ -92,7 +92,7 @@ Feature: Wallet FFI Then I wait for ffi wallet FFI_WALLET to have at least 2 contacts to be Online And I stop ffi wallet FFI_WALLET - @critical + @critical @brokenFFI Scenario: As a client I want to retrieve a list of transactions I have made and received Given I have a seed node SEED When I have a base node BASE1 connected to all seed nodes @@ -171,7 +171,7 @@ Feature: Wallet FFI Then I wait for ffi wallet FFI_WALLET to have at least 3000000 uT And I stop ffi wallet FFI_WALLET - @critical + @critical @brokenFFI Scenario: As a client I want to send a one-sided transaction Given I have a seed node SEED When I have a base node BASE1 connected to all seed nodes @@ -208,7 +208,7 @@ Feature: Wallet FFI Then wallet RECEIVER has at least 1 transactions that are all TRANSACTION_STATUS_FAUX_CONFIRMED and not cancelled And I stop ffi wallet FFI_WALLET - @critical + @critical @brokenFFI Scenario: As a client I want to receive a one-sided transaction Given I have a seed node SEED When I have a base node BASE1 connected to all seed nodes