From b3a16bf024b1a9cfa64e0c62d52c7ba3d80c747c Mon Sep 17 00:00:00 2001 From: Mateo Rico <89949621+ricomateo@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:40:42 -0300 Subject: [PATCH] feat: compute receipts root (#111) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #106 --------- Co-authored-by: Tomás Grüner <47506558+MegaRedHand@users.noreply.github.com> --- crates/core/src/types/block.rs | 22 ++++++++++++++++++++ crates/core/src/types/receipt.rs | 31 ++++++++++++++++++++++++++++ crates/core/src/types/transaction.rs | 23 +++++++++++++++++++-- 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/crates/core/src/types/block.rs b/crates/core/src/types/block.rs index 971f74236..1aeb98c59 100644 --- a/crates/core/src/types/block.rs +++ b/crates/core/src/types/block.rs @@ -1,5 +1,6 @@ use crate::{ rlp::{encode::RLPEncode, structs::Encoder}, + types::Receipt, Address, H256, U256, }; use bytes::Bytes; @@ -106,6 +107,27 @@ impl BlockBody { } } +pub fn compute_receipts_root(receipts: Vec) -> H256 { + let receipts_iter: Vec<_> = receipts + .iter() + .enumerate() + .map(|(i, receipt)| { + // Key: RLP(index) + let mut k = Vec::new(); + i.encode(&mut k); + + // Value: tx_type || RLP(receipt) if tx_type != 0 + // RLP(receipt) else + let mut v = Vec::new(); + receipt.encode_with_type(&mut v); + + (k, v) + }) + .collect(); + let root = PatriciaMerkleTree::<_, _, Keccak256>::compute_hash_from_sorted_iter(&receipts_iter); + H256(root.into()) +} + impl RLPEncode for BlockBody { fn encode(&self, buf: &mut dyn bytes::BufMut) { Encoder::new(buf) diff --git a/crates/core/src/types/receipt.rs b/crates/core/src/types/receipt.rs index 90f3195ec..9bdc4a115 100644 --- a/crates/core/src/types/receipt.rs +++ b/crates/core/src/types/receipt.rs @@ -2,17 +2,48 @@ use crate::rlp::{encode::RLPEncode, structs::Encoder}; use crate::types::Bloom; use bytes::Bytes; use ethereum_types::{Address, H256}; + +use super::TxType; pub type Index = u64; /// Result of a transaction #[derive(Clone, Debug, PartialEq, Eq)] pub struct Receipt { + tx_type: TxType, succeeded: bool, cumulative_gas_used: u64, bloom: Bloom, logs: Vec, } +impl Receipt { + pub fn new( + tx_type: TxType, + succeeded: bool, + cumulative_gas_used: u64, + bloom: Bloom, + logs: Vec, + ) -> Self { + Self { + tx_type, + succeeded, + cumulative_gas_used, + bloom, + logs, + } + } + + pub fn encode_with_type(&self, buf: &mut dyn bytes::BufMut) { + // tx_type || RLP(receipt) if tx_type != 0 + // RLP(receipt) else + match self.tx_type { + TxType::Legacy => {} + _ => buf.put_u8(self.tx_type as u8), + } + self.encode(buf); + } +} + impl RLPEncode for Receipt { fn encode(&self, buf: &mut dyn bytes::BufMut) { Encoder::new(buf) diff --git a/crates/core/src/types/transaction.rs b/crates/core/src/types/transaction.rs index cf1e2dc77..b56dfe2c0 100644 --- a/crates/core/src/types/transaction.rs +++ b/crates/core/src/types/transaction.rs @@ -284,9 +284,11 @@ fn recover_address( mod tests { use hex_literal::hex; - use super::LegacyTransaction; use crate::{ - types::{BlockBody, Transaction, TxKind}, + types::{ + compute_receipts_root, BlockBody, LegacyTransaction, Receipt, Transaction, TxKind, + TxType, + }, U256, }; @@ -315,4 +317,21 @@ mod tests { assert_eq!(result, expected_root.into()); } + + #[test] + fn test_compute_receipts_root() { + // example taken from + // https://github.com/ethereum/go-ethereum/blob/f8aa62353666a6368fb3f1a378bd0a82d1542052/cmd/evm/testdata/1/exp.json#L18 + let tx_type = TxType::Legacy; + let succeeded = true; + let cumulative_gas_used = 0x5208; + let bloom = [0x00; 256]; + let logs = vec![]; + let receipt = Receipt::new(tx_type, succeeded, cumulative_gas_used, bloom, logs); + + let result = compute_receipts_root(vec![receipt]); + let expected_root = + hex!("056b23fbba480696b65fe5a59b8f2148a1299103c4f57df839233af2cf4ca2d2"); + assert_eq!(result, expected_root.into()); + } }