From 36fc1ecd08d5968cc48debece192a0a2ca245cf2 Mon Sep 17 00:00:00 2001 From: mitchell Date: Wed, 20 Mar 2024 14:17:43 -0700 Subject: [PATCH 01/11] Add event root to block header --- crates/fuel-core/src/query/message/test.rs | 4 +-- crates/fuel-core/src/schema/block.rs | 2 +- crates/fuel-core/src/service/genesis.rs | 11 ++++--- crates/services/executor/src/executor.rs | 2 +- crates/types/src/blockchain/block.rs | 8 +++-- crates/types/src/blockchain/header.rs | 37 ++++++++++++++++------ crates/types/src/entities/coins/coin.rs | 13 ++++++++ crates/types/src/services/executor.rs | 17 +++++++++- 8 files changed, 72 insertions(+), 22 deletions(-) diff --git a/crates/fuel-core/src/query/message/test.rs b/crates/fuel-core/src/query/message/test.rs index b34b70cbc26..6e1cb2dc078 100644 --- a/crates/fuel-core/src/query/message/test.rs +++ b/crates/fuel-core/src/query/message/test.rs @@ -213,8 +213,8 @@ async fn can_build_message_proof() { .unwrap() .unwrap(); assert_eq!( - proof.message_block_header.message_receipt_root, - message_block.header().message_receipt_root + proof.message_block_header.message_outbox_root, + message_block.header().message_outbox_root ); assert_eq!( proof.message_block_header.height(), diff --git a/crates/fuel-core/src/schema/block.rs b/crates/fuel-core/src/schema/block.rs index 2233ecf35cf..b53aa1d2010 100644 --- a/crates/fuel-core/src/schema/block.rs +++ b/crates/fuel-core/src/schema/block.rs @@ -165,7 +165,7 @@ impl Header { /// Merkle root of message receipts in this block. async fn message_receipt_root(&self) -> Bytes32 { - self.0.message_receipt_root.into() + self.0.message_outbox_root.into() } /// Fuel block height. diff --git a/crates/fuel-core/src/service/genesis.rs b/crates/fuel-core/src/service/genesis.rs index fb3fbb3f61e..ca3446cae90 100644 --- a/crates/fuel-core/src/service/genesis.rs +++ b/crates/fuel-core/src/service/genesis.rs @@ -158,6 +158,9 @@ fn cleanup_genesis_progress( pub fn create_genesis_block(config: &Config) -> Block { let block_height = config.state_reader.block_height(); let da_block_height = config.state_reader.da_block_height(); + let transactions = vec![]; + let message_ids = &[]; + let events = &[]; Block::new( PartialBlockHeader { application: ApplicationHeader:: { @@ -171,17 +174,15 @@ pub fn create_genesis_block(config: &Config) -> Block { generated: Empty, }, consensus: ConsensusHeader:: { - // The genesis is a first block, so previous root is zero. prev_root: Bytes32::zeroed(), - // The block height at genesis. height: block_height, time: fuel_core_types::tai64::Tai64::UNIX_EPOCH, generated: Empty, }, }, - // Genesis block doesn't have any transaction. - vec![], - &[], + transactions, + message_ids, + events, ) } diff --git a/crates/services/executor/src/executor.rs b/crates/services/executor/src/executor.rs index ff97f4efe06..c4411cd07e8 100644 --- a/crates/services/executor/src/executor.rs +++ b/crates/services/executor/src/executor.rs @@ -504,7 +504,7 @@ where // Now that the transactions have been executed, generate the full header. - let block = block.generate(&message_ids[..]); + let block = block.generate(&message_ids[..], &events); let finalized_block_id = block.id(); diff --git a/crates/types/src/blockchain/block.rs b/crates/types/src/blockchain/block.rs index 06ecdf86058..a5c607cd972 100644 --- a/crates/types/src/blockchain/block.rs +++ b/crates/types/src/blockchain/block.rs @@ -24,6 +24,7 @@ use crate::{ ChainId, MessageId, }, + services::executor::Event, }; /// Version-able block type @@ -86,9 +87,10 @@ impl Block { header: PartialBlockHeader, transactions: Vec, message_ids: &[MessageId], + events: &[Event], ) -> Self { let inner = BlockV1 { - header: header.generate(&transactions, message_ids), + header: header.generate(&transactions, message_ids, events), transactions, }; Block::V1(inner) @@ -218,8 +220,8 @@ impl PartialFuelBlock { /// /// Message ids are produced by executed the transactions and collecting /// the ids from the receipts of messages outputs. - pub fn generate(self, message_ids: &[MessageId]) -> Block { - Block::new(self.header, self.transactions, message_ids) + pub fn generate(self, message_ids: &[MessageId], events: &[Event]) -> Block { + Block::new(self.header, self.transactions, message_ids, events) } } diff --git a/crates/types/src/blockchain/header.rs b/crates/types/src/blockchain/header.rs index 6cf0b27e319..ae28f561e3d 100644 --- a/crates/types/src/blockchain/header.rs +++ b/crates/types/src/blockchain/header.rs @@ -10,6 +10,7 @@ use super::{ }; use crate::{ fuel_merkle, + fuel_merkle::binary::root_calculator::MerkleRootCalculator, fuel_tx::Transaction, fuel_types::{ canonical::Serialize, @@ -17,6 +18,7 @@ use crate::{ Bytes32, MessageId, }, + services::executor::Event, }; use tai64::Tai64; @@ -195,7 +197,9 @@ pub struct GeneratedApplicationFields { /// Merkle root of transactions. pub transactions_root: Bytes32, /// Merkle root of message receipts in this block. - pub message_receipt_root: Bytes32, + pub message_outbox_root: Bytes32, + /// Root hash of all imported events from L1 + pub event_inbox_root: Bytes32, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -365,17 +369,31 @@ impl PartialBlockHeader { self, transactions: &[Transaction], message_ids: &[MessageId], + events: &[Event], ) -> BlockHeader { // Generate the transaction merkle root. let transactions_root = generate_txns_root(transactions); // Generate the message merkle root. - let mut message_tree = - fuel_merkle::binary::root_calculator::MerkleRootCalculator::new(); - for id in message_ids { - message_tree.push(id.as_ref()); - } - let message_receipt_root = message_tree.root().into(); + let message_outbox_root = message_ids + .iter() + .fold(MerkleRootCalculator::new(), |mut tree, id| { + tree.push(id.as_ref()); + tree + }) + .root() + .into(); + + // Generate the event merkle root. + let event_inbox_root = events + .iter() + .map(|event| event.hash()) + .fold(MerkleRootCalculator::new(), |mut tree, event| { + tree.push(event.as_ref()); + tree + }) + .root() + .into(); let application = ApplicationHeader { da_height: self.application.da_height, @@ -387,7 +405,8 @@ impl PartialBlockHeader { transactions_count: transactions.len() as u64, message_receipt_count: message_ids.len() as u64, transactions_root, - message_receipt_root, + message_outbox_root, + event_inbox_root, }, }; @@ -432,7 +451,7 @@ impl ApplicationHeader { hasher.input(self.transactions_count.to_be_bytes()); hasher.input(self.message_receipt_count.to_be_bytes()); hasher.input(self.transactions_root.as_ref()); - hasher.input(self.message_receipt_root.as_ref()); + hasher.input(self.message_outbox_root.as_ref()); hasher.input(self.consensus_parameters_version.to_bytes().as_slice()); hasher.input(self.state_transition_bytecode_version.to_bytes().as_slice()); hasher.digest() diff --git a/crates/types/src/entities/coins/coin.rs b/crates/types/src/entities/coins/coin.rs index 283eb7f25c4..bf2af9efc86 100644 --- a/crates/types/src/entities/coins/coin.rs +++ b/crates/types/src/entities/coins/coin.rs @@ -2,6 +2,7 @@ use crate::{ fuel_asm::Word, + fuel_crypto, fuel_tx::{ input::coin::{ CoinPredicate, @@ -14,6 +15,7 @@ use crate::{ fuel_types::{ Address, AssetId, + Bytes32, }, }; @@ -44,6 +46,17 @@ impl Coin { tx_pointer: self.tx_pointer, }) } + + /// Hash the inner values of the coin into a single `Bytes32` hash. + pub fn hash(&self) -> Bytes32 { + let hasher = fuel_crypto::Hasher::default() + .chain(&self.owner) + .chain(&self.amount.to_be_bytes()) + .chain(&self.asset_id) + .chain(&self.tx_pointer.block_height().to_be_bytes()) + .chain(&self.tx_pointer.tx_index().to_be_bytes()); + hasher.finalize() + } } /// The compressed version of the `Coin` with minimum fields required for diff --git a/crates/types/src/services/executor.rs b/crates/types/src/services/executor.rs index b1b3f986089..60d3b62f4aa 100644 --- a/crates/types/src/services/executor.rs +++ b/crates/types/src/services/executor.rs @@ -31,7 +31,10 @@ use crate::{ }, services::Uncommitted, }; -use std::error::Error as StdError; +use std::{ + error::Error as StdError, + ops::Deref, +}; /// The alias for executor result. pub type Result = core::result::Result; @@ -66,6 +69,18 @@ pub enum Event { CoinConsumed(Coin), } +impl Event { + /// Get the hash of the internal values of the event. + pub fn hash(&self) -> Bytes32 { + match self { + Event::MessageImported(message) => (*message.id().deref()).into(), + Event::MessageConsumed(message) => (*message.id().deref()).into(), + Event::CoinCreated(coin) => coin.hash(), + Event::CoinConsumed(coin) => coin.hash(), + } + } +} + /// The status of a transaction after it is executed. #[derive(Debug, Clone)] pub struct TransactionExecutionStatus { From a94e8bb46988b9d6cb52d352875add2fe25f58fb Mon Sep 17 00:00:00 2001 From: mitchell Date: Wed, 20 Mar 2024 15:19:53 -0700 Subject: [PATCH 02/11] Add test for event inbox root, might not be passing --- crates/fuel-core/src/database/block.rs | 2 +- crates/fuel-core/src/executor.rs | 37 ++++++++++++++++++++++ crates/fuel-core/src/query/message/test.rs | 4 +-- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/crates/fuel-core/src/database/block.rs b/crates/fuel-core/src/database/block.rs index 05bdf825a9f..0c805e717d4 100644 --- a/crates/fuel-core/src/database/block.rs +++ b/crates/fuel-core/src/database/block.rs @@ -166,7 +166,7 @@ mod tests { }, }; let block = PartialFuelBlock::new(header, vec![]); - block.generate(&[]) + block.generate(&[], &[]) }) .collect::>(); diff --git a/crates/fuel-core/src/executor.rs b/crates/fuel-core/src/executor.rs index bdceda7abc5..91346bb400f 100644 --- a/crates/fuel-core/src/executor.rs +++ b/crates/fuel-core/src/executor.rs @@ -2953,6 +2953,7 @@ mod tests { }, StorageAsMut, }; + use fuel_core_types::fuel_merkle::binary::root_calculator::MerkleRootCalculator; fn database_with_genesis_block(da_block_height: u64) -> Database { let mut db = Database::default(); @@ -3099,6 +3100,42 @@ mod tests { Ok(()) } + #[test] + fn execute_without_commit__block_producer_includes_correct_inbox_event_merkle_root( + ) { + // given + let genesis_da_height = 1u64; + let on_chain_db = database_with_genesis_block(genesis_da_height); + let mut relayer_db = Database::::default(); + let mut root_calculator = MerkleRootCalculator::new(); + let block_height = 2u32; + let relayer_da_height = 10u64; + for da_height in 0..=relayer_da_height { + let mut message = Message::default(); + message.set_da_height(da_height.into()); + message.set_nonce(da_height.into()); + root_calculator.push(message.id()); + + add_message_to_relayer(&mut relayer_db, message); + } + let expected = root_calculator.root(); + + // when + let producer = create_relayer_executor(on_chain_db, relayer_db); + let block = test_block(block_height.into(), relayer_da_height.into(), 0); + let (result, _) = producer + .execute_without_commit( + ExecutionTypes::Production(block.into()), + Default::default(), + ) + .unwrap() + .into(); + + // then + let actual = result.block.header().application().event_inbox_root; + assert_eq!(actual, expected); + } + #[test] fn block_producer_does_not_take_messages_for_the_same_height() { let genesis_da_height = 1u64; diff --git a/crates/fuel-core/src/query/message/test.rs b/crates/fuel-core/src/query/message/test.rs index 6e1cb2dc078..2ab4df3f356 100644 --- a/crates/fuel-core/src/query/message/test.rs +++ b/crates/fuel-core/src/query/message/test.rs @@ -141,7 +141,7 @@ async fn can_build_message_proof() { generated: Default::default(), }, } - .generate(&[], &[]); + .generate(&[], &[], &[]); let commit_block = CompressedBlock::test(commit_block_header, vec![]); let message_block_header = PartialBlockHeader { application: ApplicationHeader { @@ -157,7 +157,7 @@ async fn can_build_message_proof() { generated: Default::default(), }, } - .generate(&[], &message_ids); + .generate(&[], &message_ids, &[]); let message_block = CompressedBlock::test(message_block_header, TXNS.to_vec()); let block_proof = MerkleProof { From dd6b0ca0618f0b6d97b2fd35da0030dd27692559 Mon Sep 17 00:00:00 2001 From: Turner Date: Wed, 20 Mar 2024 16:43:43 -0700 Subject: [PATCH 03/11] Fix test and other compilation stuff --- crates/fuel-core/src/executor.rs | 14 +++++++------- .../consensus_module/poa/src/verifier/tests.rs | 2 +- .../services/producer/src/block_producer/tests.rs | 8 ++++---- crates/services/producer/src/mocks.rs | 2 +- crates/storage/src/structured_storage/blocks.rs | 2 +- crates/types/src/blockchain/header.rs | 2 +- crates/types/src/entities/coins/coin.rs | 10 +++++----- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/crates/fuel-core/src/executor.rs b/crates/fuel-core/src/executor.rs index 91346bb400f..45920546ece 100644 --- a/crates/fuel-core/src/executor.rs +++ b/crates/fuel-core/src/executor.rs @@ -1,5 +1,6 @@ #[allow(clippy::arithmetic_side_effects)] #[allow(clippy::cast_possible_truncation)] +#[allow(non_snake_case)] #[cfg(test)] mod tests { use crate as fuel_core; @@ -3104,21 +3105,19 @@ mod tests { fn execute_without_commit__block_producer_includes_correct_inbox_event_merkle_root( ) { // given - let genesis_da_height = 1u64; + let genesis_da_height = 3u64; let on_chain_db = database_with_genesis_block(genesis_da_height); let mut relayer_db = Database::::default(); - let mut root_calculator = MerkleRootCalculator::new(); - let block_height = 2u32; + let block_height = 1u32; let relayer_da_height = 10u64; - for da_height in 0..=relayer_da_height { + let mut root_calculator = MerkleRootCalculator::new(); + for da_height in (genesis_da_height + 1)..=relayer_da_height { let mut message = Message::default(); message.set_da_height(da_height.into()); message.set_nonce(da_height.into()); - root_calculator.push(message.id()); - + root_calculator.push(message.id().as_ref()); add_message_to_relayer(&mut relayer_db, message); } - let expected = root_calculator.root(); // when let producer = create_relayer_executor(on_chain_db, relayer_db); @@ -3132,6 +3131,7 @@ mod tests { .into(); // then + let expected = root_calculator.root().into(); let actual = result.block.header().application().event_inbox_root; assert_eq!(actual, expected); } diff --git a/crates/services/consensus_module/poa/src/verifier/tests.rs b/crates/services/consensus_module/poa/src/verifier/tests.rs index 48fe0b7ce96..d1b681191de 100644 --- a/crates/services/consensus_module/poa/src/verifier/tests.rs +++ b/crates/services/consensus_module/poa/src/verifier/tests.rs @@ -36,7 +36,7 @@ fn correct() -> Input { ..Default::default() }, }; - let block_header = partial_header.generate(&txs, &[]); + let block_header = partial_header.generate(&txs, &[], &[]); Input { block_header_merkle_root: [2u8; 32], diff --git a/crates/services/producer/src/block_producer/tests.rs b/crates/services/producer/src/block_producer/tests.rs index 3d42e753282..6bc939247e5 100644 --- a/crates/services/producer/src/block_producer/tests.rs +++ b/crates/services/producer/src/block_producer/tests.rs @@ -120,7 +120,7 @@ mod produce_and_execute_block_txpool { }, transactions: vec![], } - .generate(&[]) + .generate(&[], &[]) .compress(&Default::default()); let db = MockDb { @@ -162,7 +162,7 @@ mod produce_and_execute_block_txpool { }, transactions: vec![], } - .generate(&[]) + .generate(&[], &[]) .compress(&Default::default()); // Given @@ -215,7 +215,7 @@ mod produce_and_execute_block_txpool { }, transactions: vec![], } - .generate(&[]) + .generate(&[], &[]) .compress(&Default::default()); // Given @@ -284,7 +284,7 @@ mod produce_and_execute_block_txpool { }, transactions: vec![], } - .generate(&[]) + .generate(&[], &[]) .compress(&Default::default()); let db = MockDb { diff --git a/crates/services/producer/src/mocks.rs b/crates/services/producer/src/mocks.rs index 05aaceca133..5b0957b2126 100644 --- a/crates/services/producer/src/mocks.rs +++ b/crates/services/producer/src/mocks.rs @@ -121,7 +121,7 @@ fn to_block(component: &Components>) -> Block { .into_iter() .map(|tx| tx.as_ref().into()) .collect(); - Block::new(component.header_to_produce.clone(), transactions, &[]) + Block::new(component.header_to_produce.clone(), transactions, &[], &[]) } impl Executor> for MockExecutor { diff --git a/crates/storage/src/structured_storage/blocks.rs b/crates/storage/src/structured_storage/blocks.rs index b1720c12715..568555731cb 100644 --- a/crates/storage/src/structured_storage/blocks.rs +++ b/crates/storage/src/structured_storage/blocks.rs @@ -100,7 +100,7 @@ mod tests { }, }; let block = PartialFuelBlock::new(header, vec![]); - block.generate(&[]) + block.generate(&[], &[]) }) .collect::>(); diff --git a/crates/types/src/blockchain/header.rs b/crates/types/src/blockchain/header.rs index ae28f561e3d..3ae71540435 100644 --- a/crates/types/src/blockchain/header.rs +++ b/crates/types/src/blockchain/header.rs @@ -384,7 +384,7 @@ impl PartialBlockHeader { .root() .into(); - // Generate the event merkle root. + // Generate the inbound event merkle root. let event_inbox_root = events .iter() .map(|event| event.hash()) diff --git a/crates/types/src/entities/coins/coin.rs b/crates/types/src/entities/coins/coin.rs index bf2af9efc86..dc3f6740582 100644 --- a/crates/types/src/entities/coins/coin.rs +++ b/crates/types/src/entities/coins/coin.rs @@ -50,11 +50,11 @@ impl Coin { /// Hash the inner values of the coin into a single `Bytes32` hash. pub fn hash(&self) -> Bytes32 { let hasher = fuel_crypto::Hasher::default() - .chain(&self.owner) - .chain(&self.amount.to_be_bytes()) - .chain(&self.asset_id) - .chain(&self.tx_pointer.block_height().to_be_bytes()) - .chain(&self.tx_pointer.tx_index().to_be_bytes()); + .chain(self.owner) + .chain(self.amount.to_be_bytes()) + .chain(self.asset_id) + .chain(self.tx_pointer.block_height().to_be_bytes()) + .chain(self.tx_pointer.tx_index().to_be_bytes()); hasher.finalize() } } From 94029210c04a62be4bdc4ccdc30c5f4b4a5731c0 Mon Sep 17 00:00:00 2001 From: Turner Date: Wed, 20 Mar 2024 16:45:19 -0700 Subject: [PATCH 04/11] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9838d41329d..6b7faad5abb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ Description of the upcoming release here. ### Changed #### Breaking +- [#1769](https://github.com/FuelLabs/fuel-core/pull/1769): Include new field on header for the merkle root of imported events. Rename other message root field. - [#1768](https://github.com/FuelLabs/fuel-core/pull/1768): Moved `ContractsInfo` table to the off-chain database. Removed `salt` field from the `ContractConfig`. - [#1761](https://github.com/FuelLabs/fuel-core/pull/1761): Adjustments to the upcoming testnet configs: - Decreased the max size of the contract/predicate/script to be 100KB. From 8eb271411b14872f4d9f80174b30802ff89f299d Mon Sep 17 00:00:00 2001 From: Turner Date: Wed, 20 Mar 2024 16:50:35 -0700 Subject: [PATCH 05/11] Move stuff in the test around --- crates/fuel-core/src/executor.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/fuel-core/src/executor.rs b/crates/fuel-core/src/executor.rs index 45920546ece..1bec755dc30 100644 --- a/crates/fuel-core/src/executor.rs +++ b/crates/fuel-core/src/executor.rs @@ -3118,10 +3118,10 @@ mod tests { root_calculator.push(message.id().as_ref()); add_message_to_relayer(&mut relayer_db, message); } - - // when let producer = create_relayer_executor(on_chain_db, relayer_db); let block = test_block(block_height.into(), relayer_da_height.into(), 0); + + // when let (result, _) = producer .execute_without_commit( ExecutionTypes::Production(block.into()), From f6e6e22357634e557bbf808d5be2153483cb8f0a Mon Sep 17 00:00:00 2001 From: Turner Date: Wed, 20 Mar 2024 19:21:23 -0700 Subject: [PATCH 06/11] Use correct `Event` type and record it inside `process_da` method --- crates/fuel-core/src/database/block.rs | 2 +- crates/fuel-core/src/query/message/test.rs | 4 +-- crates/fuel-core/src/service/genesis.rs | 2 +- .../poa/src/verifier/tests.rs | 2 +- crates/services/executor/src/executor.rs | 32 ++++++++++++++++++- .../producer/src/block_producer/tests.rs | 8 ++--- crates/services/producer/src/mocks.rs | 7 +++- .../storage/src/structured_storage/blocks.rs | 2 +- crates/types/src/blockchain/block.rs | 15 ++++++--- crates/types/src/blockchain/header.rs | 14 +------- crates/types/src/entities/coins/coin.rs | 13 -------- crates/types/src/services/executor.rs | 17 +--------- crates/types/src/services/relayer.rs | 9 ++++++ 13 files changed, 68 insertions(+), 59 deletions(-) diff --git a/crates/fuel-core/src/database/block.rs b/crates/fuel-core/src/database/block.rs index 0c805e717d4..29a2e7401e5 100644 --- a/crates/fuel-core/src/database/block.rs +++ b/crates/fuel-core/src/database/block.rs @@ -166,7 +166,7 @@ mod tests { }, }; let block = PartialFuelBlock::new(header, vec![]); - block.generate(&[], &[]) + block.generate(&[], Default::default()) }) .collect::>(); diff --git a/crates/fuel-core/src/query/message/test.rs b/crates/fuel-core/src/query/message/test.rs index 2ab4df3f356..33719da25a8 100644 --- a/crates/fuel-core/src/query/message/test.rs +++ b/crates/fuel-core/src/query/message/test.rs @@ -141,7 +141,7 @@ async fn can_build_message_proof() { generated: Default::default(), }, } - .generate(&[], &[], &[]); + .generate(&[], &[], Default::default()); let commit_block = CompressedBlock::test(commit_block_header, vec![]); let message_block_header = PartialBlockHeader { application: ApplicationHeader { @@ -157,7 +157,7 @@ async fn can_build_message_proof() { generated: Default::default(), }, } - .generate(&[], &message_ids, &[]); + .generate(&[], &message_ids, Default::default()); let message_block = CompressedBlock::test(message_block_header, TXNS.to_vec()); let block_proof = MerkleProof { diff --git a/crates/fuel-core/src/service/genesis.rs b/crates/fuel-core/src/service/genesis.rs index ca3446cae90..35467614939 100644 --- a/crates/fuel-core/src/service/genesis.rs +++ b/crates/fuel-core/src/service/genesis.rs @@ -160,7 +160,7 @@ pub fn create_genesis_block(config: &Config) -> Block { let da_block_height = config.state_reader.da_block_height(); let transactions = vec![]; let message_ids = &[]; - let events = &[]; + let events = Default::default(); Block::new( PartialBlockHeader { application: ApplicationHeader:: { diff --git a/crates/services/consensus_module/poa/src/verifier/tests.rs b/crates/services/consensus_module/poa/src/verifier/tests.rs index d1b681191de..9865b915b4b 100644 --- a/crates/services/consensus_module/poa/src/verifier/tests.rs +++ b/crates/services/consensus_module/poa/src/verifier/tests.rs @@ -36,7 +36,7 @@ fn correct() -> Input { ..Default::default() }, }; - let block_header = partial_header.generate(&txs, &[], &[]); + let block_header = partial_header.generate(&txs, &[], Default::default()); Input { block_header_merkle_root: [2u8; 32], diff --git a/crates/services/executor/src/executor.rs b/crates/services/executor/src/executor.rs index c4411cd07e8..eeb5b4157c6 100644 --- a/crates/services/executor/src/executor.rs +++ b/crates/services/executor/src/executor.rs @@ -53,6 +53,7 @@ use fuel_core_types::{ RegId, Word, }, + fuel_merkle::binary::root_calculator::MerkleRootCalculator, fuel_tx::{ field::{ InputContract, @@ -304,6 +305,7 @@ pub struct ExecutionData { events: Vec, changes: Changes, pub skipped_transactions: Vec<(TxId, ExecutorError)>, + event_inbox_root: Bytes32, } /// Per-block execution options @@ -499,12 +501,13 @@ where skipped_transactions, events, changes, + event_inbox_root, .. } = execution_data; // Now that the transactions have been executed, generate the full header. - let block = block.generate(&message_ids[..], &events); + let block = block.generate(&message_ids[..], event_inbox_root); let finalized_block_id = block.id(); @@ -557,6 +560,7 @@ where events: Vec::new(), changes: Default::default(), skipped_transactions: Vec::new(), + event_inbox_root: Default::default(), }; let execution_data = &mut data; @@ -724,6 +728,29 @@ where return Err(ExecutorError::DaHeightExceededItsLimit) }; + // // Generate the message merkle root. + // let message_outbox_root = message_ids + // .iter() + // .fold(MerkleRootCalculator::new(), |mut tree, id| { + // tree.push(id.as_ref()); + // tree + // }) + // .root() + // .into(); + // + // // Generate the inbound event merkle root. + // let event_inbox_root = events + // .iter() + // .map(|event| event.hash()) + // .fold(MerkleRootCalculator::new(), |mut tree, event| { + // tree.push(event.as_ref()); + // tree + // }) + // .root() + // .into(); + + let mut root_calculator = MerkleRootCalculator::new(); + for da_height in next_unprocessed_da_height..=header.da_height.0 { let da_height = da_height.into(); let events = self @@ -731,6 +758,7 @@ where .get_events(&da_height) .map_err(|err| ExecutorError::RelayerError(err.into()))?; for event in events { + root_calculator.push(event.hash().as_ref()); match event { Event::Message(message) => { if message.da_height() != da_height { @@ -747,6 +775,8 @@ where } } + execution_data.event_inbox_root = root_calculator.root().into(); + Ok(()) } diff --git a/crates/services/producer/src/block_producer/tests.rs b/crates/services/producer/src/block_producer/tests.rs index 6bc939247e5..9366a71f225 100644 --- a/crates/services/producer/src/block_producer/tests.rs +++ b/crates/services/producer/src/block_producer/tests.rs @@ -120,7 +120,7 @@ mod produce_and_execute_block_txpool { }, transactions: vec![], } - .generate(&[], &[]) + .generate(&[], Default::default()) .compress(&Default::default()); let db = MockDb { @@ -162,7 +162,7 @@ mod produce_and_execute_block_txpool { }, transactions: vec![], } - .generate(&[], &[]) + .generate(&[], Default::default()) .compress(&Default::default()); // Given @@ -215,7 +215,7 @@ mod produce_and_execute_block_txpool { }, transactions: vec![], } - .generate(&[], &[]) + .generate(&[], Default::default()) .compress(&Default::default()); // Given @@ -284,7 +284,7 @@ mod produce_and_execute_block_txpool { }, transactions: vec![], } - .generate(&[], &[]) + .generate(&[], Default::default()) .compress(&Default::default()); let db = MockDb { diff --git a/crates/services/producer/src/mocks.rs b/crates/services/producer/src/mocks.rs index 5b0957b2126..ece2ed0673d 100644 --- a/crates/services/producer/src/mocks.rs +++ b/crates/services/producer/src/mocks.rs @@ -121,7 +121,12 @@ fn to_block(component: &Components>) -> Block { .into_iter() .map(|tx| tx.as_ref().into()) .collect(); - Block::new(component.header_to_produce.clone(), transactions, &[], &[]) + Block::new( + component.header_to_produce.clone(), + transactions, + &[], + Default::default(), + ) } impl Executor> for MockExecutor { diff --git a/crates/storage/src/structured_storage/blocks.rs b/crates/storage/src/structured_storage/blocks.rs index 568555731cb..b8f78612422 100644 --- a/crates/storage/src/structured_storage/blocks.rs +++ b/crates/storage/src/structured_storage/blocks.rs @@ -100,7 +100,7 @@ mod tests { }, }; let block = PartialFuelBlock::new(header, vec![]); - block.generate(&[], &[]) + block.generate(&[], Default::default()) }) .collect::>(); diff --git a/crates/types/src/blockchain/block.rs b/crates/types/src/blockchain/block.rs index a5c607cd972..a63f3077869 100644 --- a/crates/types/src/blockchain/block.rs +++ b/crates/types/src/blockchain/block.rs @@ -21,10 +21,10 @@ use crate::{ UniqueIdentifier, }, fuel_types::{ + Bytes32, ChainId, MessageId, }, - services::executor::Event, }; /// Version-able block type @@ -87,10 +87,10 @@ impl Block { header: PartialBlockHeader, transactions: Vec, message_ids: &[MessageId], - events: &[Event], + event_inbox_root: Bytes32, ) -> Self { let inner = BlockV1 { - header: header.generate(&transactions, message_ids, events), + header: header.generate(&transactions, message_ids, event_inbox_root), transactions, }; Block::V1(inner) @@ -220,8 +220,13 @@ impl PartialFuelBlock { /// /// Message ids are produced by executed the transactions and collecting /// the ids from the receipts of messages outputs. - pub fn generate(self, message_ids: &[MessageId], events: &[Event]) -> Block { - Block::new(self.header, self.transactions, message_ids, events) + pub fn generate(self, message_ids: &[MessageId], event_inbox_root: Bytes32) -> Block { + Block::new( + self.header, + self.transactions, + message_ids, + event_inbox_root, + ) } } diff --git a/crates/types/src/blockchain/header.rs b/crates/types/src/blockchain/header.rs index 3ae71540435..09140c0fd86 100644 --- a/crates/types/src/blockchain/header.rs +++ b/crates/types/src/blockchain/header.rs @@ -18,7 +18,6 @@ use crate::{ Bytes32, MessageId, }, - services::executor::Event, }; use tai64::Tai64; @@ -369,7 +368,7 @@ impl PartialBlockHeader { self, transactions: &[Transaction], message_ids: &[MessageId], - events: &[Event], + event_inbox_root: Bytes32, ) -> BlockHeader { // Generate the transaction merkle root. let transactions_root = generate_txns_root(transactions); @@ -384,17 +383,6 @@ impl PartialBlockHeader { .root() .into(); - // Generate the inbound event merkle root. - let event_inbox_root = events - .iter() - .map(|event| event.hash()) - .fold(MerkleRootCalculator::new(), |mut tree, event| { - tree.push(event.as_ref()); - tree - }) - .root() - .into(); - let application = ApplicationHeader { da_height: self.application.da_height, consensus_parameters_version: self.application.consensus_parameters_version, diff --git a/crates/types/src/entities/coins/coin.rs b/crates/types/src/entities/coins/coin.rs index dc3f6740582..283eb7f25c4 100644 --- a/crates/types/src/entities/coins/coin.rs +++ b/crates/types/src/entities/coins/coin.rs @@ -2,7 +2,6 @@ use crate::{ fuel_asm::Word, - fuel_crypto, fuel_tx::{ input::coin::{ CoinPredicate, @@ -15,7 +14,6 @@ use crate::{ fuel_types::{ Address, AssetId, - Bytes32, }, }; @@ -46,17 +44,6 @@ impl Coin { tx_pointer: self.tx_pointer, }) } - - /// Hash the inner values of the coin into a single `Bytes32` hash. - pub fn hash(&self) -> Bytes32 { - let hasher = fuel_crypto::Hasher::default() - .chain(self.owner) - .chain(self.amount.to_be_bytes()) - .chain(self.asset_id) - .chain(self.tx_pointer.block_height().to_be_bytes()) - .chain(self.tx_pointer.tx_index().to_be_bytes()); - hasher.finalize() - } } /// The compressed version of the `Coin` with minimum fields required for diff --git a/crates/types/src/services/executor.rs b/crates/types/src/services/executor.rs index 60d3b62f4aa..b1b3f986089 100644 --- a/crates/types/src/services/executor.rs +++ b/crates/types/src/services/executor.rs @@ -31,10 +31,7 @@ use crate::{ }, services::Uncommitted, }; -use std::{ - error::Error as StdError, - ops::Deref, -}; +use std::error::Error as StdError; /// The alias for executor result. pub type Result = core::result::Result; @@ -69,18 +66,6 @@ pub enum Event { CoinConsumed(Coin), } -impl Event { - /// Get the hash of the internal values of the event. - pub fn hash(&self) -> Bytes32 { - match self { - Event::MessageImported(message) => (*message.id().deref()).into(), - Event::MessageConsumed(message) => (*message.id().deref()).into(), - Event::CoinCreated(coin) => coin.hash(), - Event::CoinConsumed(coin) => coin.hash(), - } - } -} - /// The status of a transaction after it is executed. #[derive(Debug, Clone)] pub struct TransactionExecutionStatus { diff --git a/crates/types/src/services/relayer.rs b/crates/types/src/services/relayer.rs index dc71affee9d..2903454d112 100644 --- a/crates/types/src/services/relayer.rs +++ b/crates/types/src/services/relayer.rs @@ -3,7 +3,9 @@ use crate::{ blockchain::primitives::DaBlockHeight, entities::message::Message, + fuel_types::Bytes32, }; +use std::ops::Deref; /// The event that may come from the relayer. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -20,6 +22,13 @@ impl Event { Event::Message(message) => message.da_height(), } } + + /// Get hashed value of the event. + pub fn hash(&self) -> Bytes32 { + match self { + Event::Message(message) => (*message.id().deref()).into(), + } + } } impl From for Event { From 95663d4ed4acfa6a6c10df3042c0bd921559278a Mon Sep 17 00:00:00 2001 From: mitchell Date: Thu, 21 Mar 2024 13:29:17 -0700 Subject: [PATCH 07/11] Fix names, add getter, remove comments --- crates/client/src/client/schema/block.rs | 2 +- crates/client/src/client/types/block.rs | 4 ++-- crates/fuel-core/src/schema/block.rs | 7 ++++++- crates/services/executor/src/executor.rs | 21 --------------------- crates/types/src/blockchain/block.rs | 12 ++++++++---- crates/types/src/blockchain/header.rs | 6 +++--- tests/tests/messages.rs | 4 ++-- 7 files changed, 22 insertions(+), 34 deletions(-) diff --git a/crates/client/src/client/schema/block.rs b/crates/client/src/client/schema/block.rs index 4314f6d885a..db664086a66 100644 --- a/crates/client/src/client/schema/block.rs +++ b/crates/client/src/client/schema/block.rs @@ -124,7 +124,7 @@ pub struct Header { pub transactions_count: U64, pub message_receipt_count: U64, pub transactions_root: Bytes32, - pub message_receipt_root: Bytes32, + pub message_outbox_root: Bytes32, pub height: U32, pub prev_root: Bytes32, pub time: Tai64Timestamp, diff --git a/crates/client/src/client/types/block.rs b/crates/client/src/client/types/block.rs index a3b6531f248..2bd3cc2a7fc 100644 --- a/crates/client/src/client/types/block.rs +++ b/crates/client/src/client/types/block.rs @@ -36,7 +36,7 @@ pub struct Header { pub transactions_count: u64, pub message_receipt_count: u64, pub transactions_root: MerkleRoot, - pub message_receipt_root: MerkleRoot, + pub message_outbox_root: MerkleRoot, pub height: u32, pub prev_root: MerkleRoot, pub time: Tai64, @@ -77,7 +77,7 @@ impl From for Header { transactions_count: value.transactions_count.into(), message_receipt_count: value.message_receipt_count.into(), transactions_root: value.transactions_root.into(), - message_receipt_root: value.message_receipt_root.into(), + message_outbox_root: value.message_outbox_root.into(), height: value.height.into(), prev_root: value.prev_root.into(), time: value.time.0, diff --git a/crates/fuel-core/src/schema/block.rs b/crates/fuel-core/src/schema/block.rs index b53aa1d2010..4cda57a987a 100644 --- a/crates/fuel-core/src/schema/block.rs +++ b/crates/fuel-core/src/schema/block.rs @@ -164,10 +164,15 @@ impl Header { } /// Merkle root of message receipts in this block. - async fn message_receipt_root(&self) -> Bytes32 { + async fn message_outbox_root(&self) -> Bytes32 { self.0.message_outbox_root.into() } + /// Merkle root of inbox events in this block. + async fn event_inbox_root(&self) -> Bytes32 { + self.0.event_inbox_root.into() + } + /// Fuel block height. async fn height(&self) -> U32 { (*self.0.height()).into() diff --git a/crates/services/executor/src/executor.rs b/crates/services/executor/src/executor.rs index eeb5b4157c6..e83e003c34f 100644 --- a/crates/services/executor/src/executor.rs +++ b/crates/services/executor/src/executor.rs @@ -728,27 +728,6 @@ where return Err(ExecutorError::DaHeightExceededItsLimit) }; - // // Generate the message merkle root. - // let message_outbox_root = message_ids - // .iter() - // .fold(MerkleRootCalculator::new(), |mut tree, id| { - // tree.push(id.as_ref()); - // tree - // }) - // .root() - // .into(); - // - // // Generate the inbound event merkle root. - // let event_inbox_root = events - // .iter() - // .map(|event| event.hash()) - // .fold(MerkleRootCalculator::new(), |mut tree, event| { - // tree.push(event.as_ref()); - // tree - // }) - // .root() - // .into(); - let mut root_calculator = MerkleRootCalculator::new(); for da_height in next_unprocessed_da_height..=header.da_height.0 { diff --git a/crates/types/src/blockchain/block.rs b/crates/types/src/blockchain/block.rs index a63f3077869..fc83c9bbdbc 100644 --- a/crates/types/src/blockchain/block.rs +++ b/crates/types/src/blockchain/block.rs @@ -86,11 +86,11 @@ impl Block { pub fn new( header: PartialBlockHeader, transactions: Vec, - message_ids: &[MessageId], + outbox_message_ids: &[MessageId], event_inbox_root: Bytes32, ) -> Self { let inner = BlockV1 { - header: header.generate(&transactions, message_ids, event_inbox_root), + header: header.generate(&transactions, outbox_message_ids, event_inbox_root), transactions, }; Block::V1(inner) @@ -220,11 +220,15 @@ impl PartialFuelBlock { /// /// Message ids are produced by executed the transactions and collecting /// the ids from the receipts of messages outputs. - pub fn generate(self, message_ids: &[MessageId], event_inbox_root: Bytes32) -> Block { + pub fn generate( + self, + outbox_message_ids: &[MessageId], + event_inbox_root: Bytes32, + ) -> Block { Block::new( self.header, self.transactions, - message_ids, + outbox_message_ids, event_inbox_root, ) } diff --git a/crates/types/src/blockchain/header.rs b/crates/types/src/blockchain/header.rs index 09140c0fd86..d6a55cb7cf8 100644 --- a/crates/types/src/blockchain/header.rs +++ b/crates/types/src/blockchain/header.rs @@ -367,14 +367,14 @@ impl PartialBlockHeader { pub fn generate( self, transactions: &[Transaction], - message_ids: &[MessageId], + outbox_message_ids: &[MessageId], event_inbox_root: Bytes32, ) -> BlockHeader { // Generate the transaction merkle root. let transactions_root = generate_txns_root(transactions); // Generate the message merkle root. - let message_outbox_root = message_ids + let message_outbox_root = outbox_message_ids .iter() .fold(MerkleRootCalculator::new(), |mut tree, id| { tree.push(id.as_ref()); @@ -391,7 +391,7 @@ impl PartialBlockHeader { .state_transition_bytecode_version, generated: GeneratedApplicationFields { transactions_count: transactions.len() as u64, - message_receipt_count: message_ids.len() as u64, + message_receipt_count: outbox_message_ids.len() as u64, transactions_root, message_outbox_root, event_inbox_root, diff --git a/tests/tests/messages.rs b/tests/tests/messages.rs index 61595e3132b..598683e3fc1 100644 --- a/tests/tests/messages.rs +++ b/tests/tests/messages.rs @@ -519,7 +519,7 @@ async fn can_get_message_proof() { .map(Bytes32::from) .collect(); assert!(verify_merkle( - result.message_block_header.message_receipt_root, + result.message_block_header.message_outbox_root, &generated_message_id, message_proof_index, &message_proof_set, @@ -539,7 +539,7 @@ async fn can_get_message_proof() { // Check the root matches the proof and the root on the header. assert_eq!( - <[u8; 32]>::from(result.message_block_header.message_receipt_root), + <[u8; 32]>::from(result.message_block_header.message_outbox_root), expected_root ); From c0695577b9a1b36b496e3e8c5bb9a7134b020095 Mon Sep 17 00:00:00 2001 From: mitchell Date: Thu, 21 Mar 2024 13:40:21 -0700 Subject: [PATCH 08/11] Update schema --- crates/client/assets/schema.sdl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/client/assets/schema.sdl b/crates/client/assets/schema.sdl index d04b9fbda18..7b37606bb27 100644 --- a/crates/client/assets/schema.sdl +++ b/crates/client/assets/schema.sdl @@ -469,7 +469,11 @@ type Header { """ Merkle root of message receipts in this block. """ - messageReceiptRoot: Bytes32! + messageOutboxRoot: Bytes32! + """ + Merkle root of inbox events in this block. + """ + eventInboxRoot: Bytes32! """ Fuel block height. """ From 99cddf33eae9edc3382585bb39bb3ebc5de7b7aa Mon Sep 17 00:00:00 2001 From: mitchell Date: Thu, 21 Mar 2024 13:51:55 -0700 Subject: [PATCH 09/11] Fix snapshots --- crates/client/src/client/schema/block.rs | 1 + ...schema__block__tests__block_by_height_query_gql_output.snap | 3 ++- ...nt__schema__block__tests__block_by_id_query_gql_output.snap | 3 ++- ...hema__block__tests__blocks_connection_query_gql_output.snap | 3 ++- ...__client__schema__chain__tests__chain_gql_query_output.snap | 3 ++- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/crates/client/src/client/schema/block.rs b/crates/client/src/client/schema/block.rs index db664086a66..4fecdb0e4bc 100644 --- a/crates/client/src/client/schema/block.rs +++ b/crates/client/src/client/schema/block.rs @@ -125,6 +125,7 @@ pub struct Header { pub message_receipt_count: U64, pub transactions_root: Bytes32, pub message_outbox_root: Bytes32, + pub event_inbox_root: Bytes32, pub height: U32, pub prev_root: Bytes32, pub time: Tai64Timestamp, diff --git a/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__block__tests__block_by_height_query_gql_output.snap b/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__block__tests__block_by_height_query_gql_output.snap index 7664a8db6ff..99321c4eb66 100644 --- a/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__block__tests__block_by_height_query_gql_output.snap +++ b/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__block__tests__block_by_height_query_gql_output.snap @@ -13,7 +13,8 @@ query($height: U32) { transactionsCount messageReceiptCount transactionsRoot - messageReceiptRoot + messageOutboxRoot + eventInboxRoot height prevRoot time diff --git a/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__block__tests__block_by_id_query_gql_output.snap b/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__block__tests__block_by_id_query_gql_output.snap index b6c69071fba..5d4d9dbd8ca 100644 --- a/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__block__tests__block_by_id_query_gql_output.snap +++ b/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__block__tests__block_by_id_query_gql_output.snap @@ -13,7 +13,8 @@ query($id: BlockId) { transactionsCount messageReceiptCount transactionsRoot - messageReceiptRoot + messageOutboxRoot + eventInboxRoot height prevRoot time diff --git a/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__block__tests__blocks_connection_query_gql_output.snap b/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__block__tests__blocks_connection_query_gql_output.snap index e4f395ec340..67034b77090 100644 --- a/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__block__tests__blocks_connection_query_gql_output.snap +++ b/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__block__tests__blocks_connection_query_gql_output.snap @@ -16,7 +16,8 @@ query($after: String, $before: String, $first: Int, $last: Int) { transactionsCount messageReceiptCount transactionsRoot - messageReceiptRoot + messageOutboxRoot + eventInboxRoot height prevRoot time diff --git a/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__chain__tests__chain_gql_query_output.snap b/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__chain__tests__chain_gql_query_output.snap index 252aad25e37..74f755e8e58 100644 --- a/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__chain__tests__chain_gql_query_output.snap +++ b/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__chain__tests__chain_gql_query_output.snap @@ -16,7 +16,8 @@ query { transactionsCount messageReceiptCount transactionsRoot - messageReceiptRoot + messageOutboxRoot + eventInboxRoot height prevRoot time From 646cfbf2b7b638de976d766a639c5361ef60615c Mon Sep 17 00:00:00 2001 From: mitchell Date: Thu, 21 Mar 2024 15:26:44 -0700 Subject: [PATCH 10/11] Include field in client header type --- crates/client/src/client/types/block.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/client/src/client/types/block.rs b/crates/client/src/client/types/block.rs index 2bd3cc2a7fc..4a2a59065bb 100644 --- a/crates/client/src/client/types/block.rs +++ b/crates/client/src/client/types/block.rs @@ -37,6 +37,7 @@ pub struct Header { pub message_receipt_count: u64, pub transactions_root: MerkleRoot, pub message_outbox_root: MerkleRoot, + pub event_inbox_root: MerkleRoot, pub height: u32, pub prev_root: MerkleRoot, pub time: Tai64, From 54de938b56507e67a9336a512d88192dfe10f9ef Mon Sep 17 00:00:00 2001 From: mitchell Date: Thu, 21 Mar 2024 15:35:24 -0700 Subject: [PATCH 11/11] Include field in `From` constructor --- crates/client/src/client/types/block.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/client/src/client/types/block.rs b/crates/client/src/client/types/block.rs index 4a2a59065bb..122bfe08660 100644 --- a/crates/client/src/client/types/block.rs +++ b/crates/client/src/client/types/block.rs @@ -79,6 +79,7 @@ impl From for Header { message_receipt_count: value.message_receipt_count.into(), transactions_root: value.transactions_root.into(), message_outbox_root: value.message_outbox_root.into(), + event_inbox_root: value.event_inbox_root.into(), height: value.height.into(), prev_root: value.prev_root.into(), time: value.time.0,