Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keep record of events from L1 in Block Header #1769

Merged
merged 11 commits into from
Mar 22, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion crates/fuel-core/src/database/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ mod tests {
},
};
let block = PartialFuelBlock::new(header, vec![]);
block.generate(&[])
block.generate(&[], &[])
})
.collect::<Vec<_>>();

Expand Down
37 changes: 37 additions & 0 deletions crates/fuel-core/src/executor.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -2953,6 +2954,7 @@ mod tests {
},
StorageAsMut,
};
use fuel_core_types::fuel_merkle::binary::root_calculator::MerkleRootCalculator;

fn database_with_genesis_block(da_block_height: u64) -> Database<OnChain> {
let mut db = Database::default();
Expand Down Expand Up @@ -3099,6 +3101,41 @@ mod tests {
Ok(())
}

#[test]
fn execute_without_commit__block_producer_includes_correct_inbox_event_merkle_root(
) {
// given
let genesis_da_height = 3u64;
let on_chain_db = database_with_genesis_block(genesis_da_height);
let mut relayer_db = Database::<Relayer>::default();
let block_height = 1u32;
let relayer_da_height = 10u64;
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().as_ref());
add_message_to_relayer(&mut relayer_db, message);
}
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()),
Default::default(),
)
.unwrap()
.into();

// then
let expected = root_calculator.root().into();
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;
Expand Down
8 changes: 4 additions & 4 deletions crates/fuel-core/src/query/message/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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(),
Expand Down
2 changes: 1 addition & 1 deletion crates/fuel-core/src/schema/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ impl Header {

/// Merkle root of message receipts in this block.
async fn message_receipt_root(&self) -> Bytes32 {
Voxelot marked this conversation as resolved.
Show resolved Hide resolved
self.0.message_receipt_root.into()
self.0.message_outbox_root.into()
}

Voxelot marked this conversation as resolved.
Show resolved Hide resolved
/// Fuel block height.
Expand Down
11 changes: 6 additions & 5 deletions crates/fuel-core/src/service/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<Empty> {
Expand All @@ -171,17 +174,15 @@ pub fn create_genesis_block(config: &Config) -> Block {
generated: Empty,
},
consensus: ConsensusHeader::<Empty> {
// 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,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
2 changes: 1 addition & 1 deletion crates/services/executor/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down
8 changes: 4 additions & 4 deletions crates/services/producer/src/block_producer/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ mod produce_and_execute_block_txpool {
},
transactions: vec![],
}
.generate(&[])
.generate(&[], &[])
.compress(&Default::default());

let db = MockDb {
Expand Down Expand Up @@ -162,7 +162,7 @@ mod produce_and_execute_block_txpool {
},
transactions: vec![],
}
.generate(&[])
.generate(&[], &[])
.compress(&Default::default());

// Given
Expand Down Expand Up @@ -215,7 +215,7 @@ mod produce_and_execute_block_txpool {
},
transactions: vec![],
}
.generate(&[])
.generate(&[], &[])
.compress(&Default::default());

// Given
Expand Down Expand Up @@ -284,7 +284,7 @@ mod produce_and_execute_block_txpool {
},
transactions: vec![],
}
.generate(&[])
.generate(&[], &[])
.compress(&Default::default());

let db = MockDb {
Expand Down
2 changes: 1 addition & 1 deletion crates/services/producer/src/mocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ fn to_block(component: &Components<Vec<ArcPoolTx>>) -> 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<Vec<ArcPoolTx>> for MockExecutor {
Expand Down
2 changes: 1 addition & 1 deletion crates/storage/src/structured_storage/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ mod tests {
},
};
let block = PartialFuelBlock::new(header, vec![]);
block.generate(&[])
block.generate(&[], &[])
})
.collect::<Vec<_>>();

Expand Down
8 changes: 5 additions & 3 deletions crates/types/src/blockchain/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use crate::{
ChainId,
MessageId,
},
services::executor::Event,
};

/// Version-able block type
Expand Down Expand Up @@ -86,9 +87,10 @@ impl Block<Transaction> {
header: PartialBlockHeader,
transactions: Vec<Transaction>,
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)
Expand Down Expand Up @@ -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)
}
}

Expand Down
37 changes: 28 additions & 9 deletions crates/types/src/blockchain/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ use super::{
};
use crate::{
fuel_merkle,
fuel_merkle::binary::root_calculator::MerkleRootCalculator,
fuel_tx::Transaction,
fuel_types::{
canonical::Serialize,
BlockHeight,
Bytes32,
MessageId,
},
services::executor::Event,
};
use tai64::Tai64;

Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -365,17 +369,31 @@ impl PartialBlockHeader {
self,
transactions: &[Transaction],
message_ids: &[MessageId],
events: &[Event],
MitchTurner marked this conversation as resolved.
Show resolved Hide resolved
) -> 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 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,
Expand All @@ -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,
},
};

Expand Down Expand Up @@ -432,7 +451,7 @@ impl ApplicationHeader<GeneratedApplicationFields> {
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()
Expand Down
13 changes: 13 additions & 0 deletions crates/types/src/entities/coins/coin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use crate::{
fuel_asm::Word,
fuel_crypto,
fuel_tx::{
input::coin::{
CoinPredicate,
Expand All @@ -14,6 +15,7 @@ use crate::{
fuel_types::{
Address,
AssetId,
Bytes32,
},
};

Expand Down Expand Up @@ -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
Expand Down
17 changes: 16 additions & 1 deletion crates/types/src/services/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> = core::result::Result<T, Error>;
Expand Down Expand Up @@ -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 {
Expand Down
Loading