diff --git a/crates/core/src/types/block.rs b/crates/core/src/types/block.rs index 971f742362e..1aeb98c5966 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 90f3195ec83..9bdc4a115f0 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 cf1e2dc7721..b56dfe2c075 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()); + } }