From 240eb87cb48910bacb2cb8e1479c878b745ed7bc Mon Sep 17 00:00:00 2001 From: Hantang Sun Date: Wed, 8 May 2024 01:35:18 +0800 Subject: [PATCH 1/3] Etherlink: getBlockBy* RPC returns base fee per gas and mix_hash --- .../lib_dev/encodings/ethereum_types.ml | 241 +++++++++++++----- .../lib_dev/encodings/ethereum_types.mli | 4 + etherlink/kernel_evm/Cargo.lock | 2 + etherlink/kernel_evm/Cargo.toml | 1 + etherlink/kernel_evm/ethereum/Cargo.toml | 2 + etherlink/kernel_evm/ethereum/src/block.rs | 180 ++++++++----- .../kernel_evm/ethereum/src/rlp_helpers.rs | 8 +- etherlink/kernel_evm/kernel/Cargo.toml | 2 + .../kernel/src/block_in_progress.rs | 5 +- etherlink/kernel_evm/kernel/src/simulation.rs | 6 + etherlink/kernel_evm/kernel/src/storage.rs | 9 +- etherlink/tezt/lib/block.ml | 13 + etherlink/tezt/lib/block.mli | 2 + 13 files changed, 351 insertions(+), 124 deletions(-) diff --git a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml index be5b5078b09d..c48d53637000 100644 --- a/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml +++ b/etherlink/bin_node/lib_dev/encodings/ethereum_types.ml @@ -665,6 +665,10 @@ type block = { timestamp : quantity; transactions : block_transactions; uncles : hash list; + (* baseFeePerGas and mixHash are set optionnal because old blocks didn't have + them*) + baseFeePerGas : quantity option; + mixHash : block_hash option; } let decode_list decoder list = @@ -679,7 +683,7 @@ let decode_option ~default decoder bytes = (if bytes = Bytes.empty then None else Some (decoder bytes)) |> Option.value ~default -let block_from_rlp bytes = +let block_from_rlp_v0 bytes = match Rlp.decode bytes with | Ok (Rlp.List @@ -767,9 +771,115 @@ let block_from_rlp bytes = transactions; (* Post merge: always empty. *) uncles = []; + baseFeePerGas = None; + mixHash = None; } | _ -> raise (Invalid_argument "Expected a List of 13 elements") +let block_from_rlp_v1 bytes = + match Rlp.decode bytes with + | Ok + (Rlp.List + [ + Value number; + Value hash; + Value parent_hash; + Value logsBloom; + Value transactionRoot; + Value stateRoot; + Value receiptRoot; + Value miner; + Value extraData; + Value gasLimit; + List transactions; + Value gasUsed; + Value timestamp; + Value baseFeePerGas; + Value mixHash; + ]) -> + let (Qty number) = decode_number number in + let hash = decode_block_hash hash in + let parent = decode_block_hash parent_hash in + let logsBloom = + decode_option ~default:(Hex (String.make 512 'a')) decode_hex logsBloom + in + (* Post merge: this field is now used for the "fee recipient". We don't + have that, potentially this could be the sequencer. *) + let miner = + decode_option + ~default:(Hex "0000000000000000000000000000000000000000") + decode_hex + miner + in + let transactionRoot = + decode_option + ~default:(Hash (Hex (String.make 64 'a'))) + decode_hash + transactionRoot + in + let stateRoot = + decode_option + ~default:(Hash (Hex (String.make 64 'a'))) + decode_hash + stateRoot + in + let receiptRoot = + decode_option + ~default:(Hash (Hex (String.make 64 'a'))) + decode_hash + receiptRoot + in + let extraData = decode_option ~default:(Hex "") decode_hex extraData in + let gasLimit = + decode_option ~default:(Qty Z.zero) decode_number gasLimit + in + let transactions = TxHash (decode_list decode_hash transactions) in + let gasUsed = decode_number gasUsed in + let timestamp = decode_number timestamp in + let baseFeePerGas = Some (decode_number baseFeePerGas) in + let mixHash = Some (decode_block_hash mixHash) in + { + number = Qty number; + hash; + parent; + (* Post merge: always 0. *) + nonce = Hex "0000000000000000"; + (* Post merge: uncles are always empty, therefore this is the "empty" + hash of these uncles. *) + sha3Uncles = + Hash + (Hex + "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"); + logsBloom; + transactionRoot; + stateRoot; + receiptRoot; + miner; + (* Post merge: always zero. *) + difficulty = Qty Z.zero; + (* Post merge: sum of difficulty will always be zero because difficulty + has and will always be zero. *) + totalDifficulty = Qty Z.zero; + extraData; + size = Qty (Z.of_int (Bytes.length bytes)); + gasLimit; + gasUsed; + timestamp; + transactions; + (* Post merge: always empty. *) + uncles = []; + baseFeePerGas; + mixHash; + } + | _ -> raise (Invalid_argument "Expected a List of 15 elements") + +let block_from_rlp bytes = + let first_byte = Bytes.get bytes 0 in + if first_byte = Char.chr 1 then + let length = Bytes.length bytes in + block_from_rlp_v1 (Bytes.sub bytes 1 (length - 1)) + else block_from_rlp_v0 bytes + let block_encoding = let open Data_encoding in conv @@ -793,45 +903,51 @@ let block_encoding = timestamp; transactions; uncles; + baseFeePerGas; + mixHash; } -> - ( ( number, - hash, - parent, - nonce, - sha3Uncles, - logsBloom, - transactionRoot, - stateRoot, - receiptRoot, - miner ), - ( difficulty, - totalDifficulty, - extraData, - size, - gasLimit, - gasUsed, - timestamp, - transactions, - uncles ) )) - (fun ( ( number, - hash, - parent, - nonce, - sha3Uncles, - logsBloom, - transactionRoot, - stateRoot, - receiptRoot, - miner ), - ( difficulty, - totalDifficulty, - extraData, - size, - gasLimit, - gasUsed, - timestamp, - transactions, - uncles ) ) -> + ( ( ( number, + hash, + parent, + nonce, + sha3Uncles, + logsBloom, + transactionRoot, + stateRoot, + receiptRoot, + miner ), + ( difficulty, + totalDifficulty, + extraData, + size, + gasLimit, + gasUsed, + timestamp, + transactions, + uncles, + baseFeePerGas ) ), + mixHash )) + (fun ( ( ( number, + hash, + parent, + nonce, + sha3Uncles, + logsBloom, + transactionRoot, + stateRoot, + receiptRoot, + miner ), + ( difficulty, + totalDifficulty, + extraData, + size, + gasLimit, + gasUsed, + timestamp, + transactions, + uncles, + baseFeePerGas ) ), + mixHash ) -> { number; hash; @@ -849,32 +965,37 @@ let block_encoding = size; gasLimit; gasUsed; + baseFeePerGas; timestamp; transactions; uncles; + mixHash; }) (merge_objs - (obj10 - (req "number" quantity_encoding) - (req "hash" block_hash_encoding) - (req "parentHash" block_hash_encoding) - (req "nonce" hex_encoding) - (req "sha3Uncles" hash_encoding) - (req "logsBloom" hex_encoding) - (req "transactionsRoot" hash_encoding) - (req "stateRoot" hash_encoding) - (req "receiptsRoot" hash_encoding) - (req "miner" hex_encoding)) - (obj9 - (req "difficulty" quantity_encoding) - (req "totalDifficulty" quantity_encoding) - (req "extraData" hex_encoding) - (req "size" quantity_encoding) - (req "gasLimit" quantity_encoding) - (req "gasUsed" quantity_encoding) - (req "timestamp" quantity_encoding) - (req "transactions" block_transactions_encoding) - (req "uncles" (list hash_encoding)))) + (merge_objs + (obj10 + (req "number" quantity_encoding) + (req "hash" block_hash_encoding) + (req "parentHash" block_hash_encoding) + (req "nonce" hex_encoding) + (req "sha3Uncles" hash_encoding) + (req "logsBloom" hex_encoding) + (req "transactionsRoot" hash_encoding) + (req "stateRoot" hash_encoding) + (req "receiptsRoot" hash_encoding) + (req "miner" hex_encoding)) + (obj10 + (req "difficulty" quantity_encoding) + (req "totalDifficulty" quantity_encoding) + (req "extraData" hex_encoding) + (req "size" quantity_encoding) + (req "gasLimit" quantity_encoding) + (req "gasUsed" quantity_encoding) + (req "timestamp" quantity_encoding) + (req "transactions" block_transactions_encoding) + (req "uncles" (list hash_encoding)) + (opt "baseFeePerGas" quantity_encoding))) + (obj1 (opt "mixHash" block_hash_encoding))) type transaction = { from : address; diff --git a/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli b/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli index ae5e411bcbea..f35591bfbdd9 100644 --- a/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli +++ b/etherlink/bin_node/lib_dev/encodings/ethereum_types.mli @@ -151,6 +151,10 @@ type block = { timestamp : quantity; transactions : block_transactions; uncles : hash list; + (* baseFeePerGas and mixHash are set optionnal because old blocks didn't have + them*) + baseFeePerGas : quantity option; + mixHash : block_hash option; } val block_encoding : block Data_encoding.t diff --git a/etherlink/kernel_evm/Cargo.lock b/etherlink/kernel_evm/Cargo.lock index 764639534956..c28b29080bab 100644 --- a/etherlink/kernel_evm/Cargo.lock +++ b/etherlink/kernel_evm/Cargo.lock @@ -603,6 +603,7 @@ name = "evm_kernel" version = "0.1.0" dependencies = [ "anyhow", + "bytes", "ethbloom", "ethereum", "evm", @@ -2167,6 +2168,7 @@ name = "tezos_ethereum" version = "0.1.0" dependencies = [ "anyhow", + "bytes", "ethbloom", "ethereum", "hex", diff --git a/etherlink/kernel_evm/Cargo.toml b/etherlink/kernel_evm/Cargo.toml index 0e676b8dd758..f4b1ff07ce4c 100644 --- a/etherlink/kernel_evm/Cargo.toml +++ b/etherlink/kernel_evm/Cargo.toml @@ -31,6 +31,7 @@ num-traits = "0.2.8" ethereum = { version = "0.14.0", default-features = false } ethbloom = { version = "0.13.0", default-features = false, features = ["rlp"] } softfloat = "1.0.0" +bytes = "^1" # serialization hex = "0.4" diff --git a/etherlink/kernel_evm/ethereum/Cargo.toml b/etherlink/kernel_evm/ethereum/Cargo.toml index e66988aff386..657fd964775b 100644 --- a/etherlink/kernel_evm/ethereum/Cargo.toml +++ b/etherlink/kernel_evm/ethereum/Cargo.toml @@ -21,6 +21,8 @@ ethbloom.workspace = true rlp.workspace = true hex.workspace = true +bytes.workspace = true + sha3.workspace = true tezos_crypto_rs.workspace = true tezos_data_encoding = "0.5" diff --git a/etherlink/kernel_evm/ethereum/src/block.rs b/etherlink/kernel_evm/ethereum/src/block.rs index d33f923f54f7..65508c9fd6a3 100644 --- a/etherlink/kernel_evm/ethereum/src/block.rs +++ b/etherlink/kernel_evm/ethereum/src/block.rs @@ -9,11 +9,12 @@ use crate::rlp_helpers::{ append_option_explicit, append_timestamp, append_u256_le, append_u64_le, decode_field, decode_field_h256, decode_field_u256_le, decode_field_u64_le, decode_option_explicit, decode_timestamp, decode_transaction_hash_list, next, + VersionedEncoding, }; use crate::transaction::TransactionHash; use ethbloom::Bloom; use primitive_types::{H160, H256, U256}; -use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; +use rlp::{DecoderError, Rlp, RlpStream}; use sha3::{Digest, Keccak256}; use tezos_smart_rollup_encoding::timestamp::Timestamp; @@ -137,20 +138,11 @@ pub struct L2Block { pub gas_used: U256, pub timestamp: Timestamp, pub transactions: Vec, + pub base_fee_per_gas: U256, + pub mix_hash: H256, } impl L2Block { - const DUMMY_HASH: &str = "00000000000000000000000000000000"; - const BLOCK_HASH_SIZE: usize = 32; - - fn dummy_block_hash() -> H256 { - H256([0; L2Block::BLOCK_HASH_SIZE]) - } - - pub fn dummy_hash() -> OwnedHash { - L2Block::DUMMY_HASH.into() - } - #[allow(clippy::too_many_arguments)] pub fn new( number: U256, @@ -163,6 +155,7 @@ impl L2Block { receipts_root: OwnedHash, gas_used: U256, gas_limit: u64, + base_fee_per_gas: U256, ) -> Self { let hash = Self::hash( parent_hash, @@ -191,6 +184,8 @@ impl L2Block { gas_limit, extra_data: None, miner: None, + base_fee_per_gas, + mix_hash: H256::zero(), } } @@ -242,53 +237,69 @@ impl L2Block { let bytes: Vec = rlp::encode_list::(&header).into(); H256(Keccak256::digest(bytes).into()) } -} -impl Default for L2Block { - fn default() -> Self { - Self { - number: U256::default(), - hash: H256::default(), - parent_hash: L2Block::dummy_block_hash(), - logs_bloom: Bloom::default(), - transactions_root: L2Block::dummy_hash(), - state_root: L2Block::dummy_hash(), - receipts_root: L2Block::dummy_hash(), - miner: None, - extra_data: None, - gas_limit: 1 << 50, - gas_used: U256::zero(), - timestamp: Timestamp::from(0), - transactions: Vec::new(), + pub fn from_bytes(bytes: &[u8]) -> Result { + let first = *bytes.first().ok_or(DecoderError::Custom("Empty bytes"))?; + if first == 0x01 { + let decoder = Rlp::new(&bytes[1..]); + Self::rlp_decode_v1(&decoder) + } else { + let decoder = Rlp::new(bytes); + Self::rlp_decode_v0(&decoder) } } -} -impl Encodable for L2Block { - fn rlp_append(&self, s: &mut RlpStream) { - s.begin_list(13); - append_u256_le(s, &self.number); - s.append(&self.hash); - s.append(&self.parent_hash); - s.append(&self.logs_bloom); - s.append(&self.transactions_root); - s.append(&self.state_root); - s.append(&self.receipts_root); - append_option_explicit(s, &self.miner, RlpStream::append); - append_option_explicit(s, &self.extra_data, RlpStream::append); - append_u64_le(s, &self.gas_limit); - let transactions_bytes: Vec> = - self.transactions.iter().map(|x| x.to_vec()).collect(); - s.append_list::, _>(&transactions_bytes); - append_u256_le(s, &self.gas_used); - append_timestamp(s, self.timestamp); + fn rlp_decode_v0(decoder: &Rlp) -> Result { + if decoder.is_list() { + if Ok(13) == decoder.item_count() { + let mut it = decoder.iter(); + let number: U256 = decode_field_u256_le(&next(&mut it)?, "number")?; + let hash: H256 = decode_field_h256(&next(&mut it)?, "hash")?; + let parent_hash: H256 = + decode_field_h256(&next(&mut it)?, "parent_hash")?; + let logs_bloom: Bloom = decode_field(&next(&mut it)?, "logs_bloom")?; + let transactions_root: OwnedHash = + decode_field(&next(&mut it)?, "transactions_root")?; + let state_root: OwnedHash = decode_field(&next(&mut it)?, "state_root")?; + let receipts_root: OwnedHash = + decode_field(&next(&mut it)?, "receipts_root")?; + let miner: Option = + decode_option_explicit(&next(&mut it)?, "miner", decode_field)?; + let extra_data: Option = + decode_option_explicit(&next(&mut it)?, "extra_data", decode_field)?; + let gas_limit = decode_field_u64_le(&next(&mut it)?, "gas_limit")?; + let transactions: Vec = + decode_transaction_hash_list(&next(&mut it)?, "transactions")?; + let gas_used: U256 = decode_field_u256_le(&next(&mut it)?, "gas_used")?; + let timestamp = decode_timestamp(&next(&mut it)?)?; + Ok(L2Block { + number, + hash, + parent_hash, + logs_bloom, + transactions_root, + state_root, + receipts_root, + miner, + extra_data, + gas_limit, + gas_used, + timestamp, + transactions, + base_fee_per_gas: U256::from(1000000000), + mix_hash: H256::zero(), + }) + } else { + Err(DecoderError::RlpIncorrectListLen) + } + } else { + Err(DecoderError::RlpExpectedToBeList) + } } -} -impl Decodable for L2Block { - fn decode(decoder: &Rlp) -> Result { + fn rlp_decode_v1(decoder: &Rlp) -> Result { if decoder.is_list() { - if Ok(13) == decoder.item_count() { + if Ok(15) == decoder.item_count() { let mut it = decoder.iter(); let number: U256 = decode_field_u256_le(&next(&mut it)?, "number")?; let hash: H256 = decode_field_h256(&next(&mut it)?, "hash")?; @@ -309,6 +320,9 @@ impl Decodable for L2Block { decode_transaction_hash_list(&next(&mut it)?, "transactions")?; let gas_used: U256 = decode_field_u256_le(&next(&mut it)?, "gas_used")?; let timestamp = decode_timestamp(&next(&mut it)?)?; + let base_fee_per_gas: U256 = + decode_field_u256_le(&next(&mut it)?, "base_fee_per_gas")?; + let mix_hash: H256 = decode_field_h256(&next(&mut it)?, "mix_hash")?; Ok(L2Block { number, hash, @@ -323,6 +337,8 @@ impl Decodable for L2Block { gas_used, timestamp, transactions, + base_fee_per_gas, + mix_hash, }) } else { Err(DecoderError::RlpIncorrectListLen) @@ -331,24 +347,65 @@ impl Decodable for L2Block { Err(DecoderError::RlpExpectedToBeList) } } + + fn rlp_encode(self: &L2Block, s: &mut RlpStream) { + s.begin_list(15); + append_u256_le(s, &self.number); + s.append(&self.hash); + s.append(&self.parent_hash); + s.append(&self.logs_bloom); + s.append(&self.transactions_root); + s.append(&self.state_root); + s.append(&self.receipts_root); + append_option_explicit(s, &self.miner, RlpStream::append); + append_option_explicit(s, &self.extra_data, RlpStream::append); + append_u64_le(s, &self.gas_limit); + let transactions_bytes: Vec> = + self.transactions.iter().map(|x| x.to_vec()).collect(); + s.append_list::, _>(&transactions_bytes); + append_u256_le(s, &self.gas_used); + append_timestamp(s, self.timestamp); + append_u256_le(s, &self.base_fee_per_gas); + s.append(&self.mix_hash); + } +} + +impl VersionedEncoding for L2Block { + const VERSION: u8 = 1; + + fn unversionned_encode(&self) -> bytes::BytesMut { + let mut s = RlpStream::new(); + self.rlp_encode(&mut s); + s.out() + } + + fn unversionned_decode(decoder: &Rlp) -> Result { + Self::rlp_decode_v1(decoder) + } } #[cfg(test)] mod tests { use super::L2Block; - use crate::rlp_helpers::FromRlpBytes; + use crate::eth_gen::OwnedHash; + use crate::rlp_helpers::VersionedEncoding; use crate::transaction::TRANSACTION_HASH_SIZE; + use crate::Bloom; use primitive_types::{H256, U256}; - use rlp::Encodable; use tezos_smart_rollup_encoding::timestamp::Timestamp; fn block_encoding_roundtrip(v: L2Block) { - let bytes = v.rlp_bytes(); - let v2 = L2Block::from_rlp_bytes(&bytes).expect("L2Block should be decodable"); + let bytes = v.to_bytes(); + let v2 = L2Block::from_bytes(&bytes).expect("L2Block should be decodable"); assert_eq!(v, v2, "Roundtrip failed on {:?}", v) } + const DUMMY_HASH: &str = "00000000000000000000000000000000"; + + pub fn dummy_hash() -> OwnedHash { + DUMMY_HASH.into() + } fn dummy_block(tx_length: usize) -> L2Block { L2Block { number: U256::from(42), @@ -356,7 +413,16 @@ mod tests { parent_hash: H256::from([2u8; 32]), timestamp: Timestamp::from(10i64), transactions: vec![[0u8; TRANSACTION_HASH_SIZE]; tx_length], - ..Default::default() + logs_bloom: Bloom::default(), + transactions_root: dummy_hash(), + state_root: dummy_hash(), + receipts_root: dummy_hash(), + miner: None, + extra_data: None, + gas_limit: 1 << 50, + gas_used: U256::zero(), + base_fee_per_gas: U256::zero(), + mix_hash: H256::default(), } } diff --git a/etherlink/kernel_evm/ethereum/src/rlp_helpers.rs b/etherlink/kernel_evm/ethereum/src/rlp_helpers.rs index 95597ee9e27d..03f016947e35 100644 --- a/etherlink/kernel_evm/ethereum/src/rlp_helpers.rs +++ b/etherlink/kernel_evm/ethereum/src/rlp_helpers.rs @@ -372,8 +372,10 @@ pub fn decode_public_key(decoder: &Rlp<'_>) -> Result { Ok(pk) } -pub trait VersionedEncoding: Encodable + Decodable { +pub trait VersionedEncoding: std::marker::Sized { const VERSION: u8; + fn unversionned_encode(&self) -> bytes::BytesMut; + fn unversionned_decode(decoder: &Rlp) -> Result; /// from_bytes is never used outside of tests. If needed, it needs to be /// implemented explicitly outside of the trait. @@ -382,14 +384,14 @@ pub trait VersionedEncoding: Encodable + Decodable { let tag = vec[0]; if tag == Self::VERSION { let decoder = Rlp::new(&vec[1..]); - Self::decode(&decoder) + Self::unversionned_decode(&decoder) } else { Err(DecoderError::Custom("Decoding on unknown version")) } } fn to_bytes(&self) -> Vec { - let mut bytes: Vec = self.rlp_bytes().into(); + let mut bytes: Vec = self.unversionned_encode().into(); bytes.insert(0, Self::VERSION); bytes } diff --git a/etherlink/kernel_evm/kernel/Cargo.toml b/etherlink/kernel_evm/kernel/Cargo.toml index 071856d7cd4f..b97601377d67 100644 --- a/etherlink/kernel_evm/kernel/Cargo.toml +++ b/etherlink/kernel_evm/kernel/Cargo.toml @@ -26,6 +26,8 @@ softfloat.workspace = true rlp.workspace = true hex.workspace = true +bytes.worspace = true + sha3.workspace = true libsecp256k1.workspace = true tezos_crypto_rs.workspace = true diff --git a/etherlink/kernel_evm/kernel/src/block_in_progress.rs b/etherlink/kernel_evm/kernel/src/block_in_progress.rs index 910271993342..fda3f3c63204 100644 --- a/etherlink/kernel_evm/kernel/src/block_in_progress.rs +++ b/etherlink/kernel_evm/kernel/src/block_in_progress.rs @@ -8,6 +8,7 @@ use crate::apply::{TransactionObjectInfo, TransactionReceiptInfo}; use crate::error::Error; use crate::error::TransferError::CumulativeGasUsedOverflow; +use crate::gas_price::base_fee_per_gas; use crate::inbox::Transaction; use crate::safe_storage::KernelRuntime; use crate::storage; @@ -279,7 +280,7 @@ impl BlockInProgress { ) -> Result, anyhow::Error> { match host.store_get_hash(path) { Ok(hash) => Ok(hash), - _ => Ok(L2Block::dummy_hash()), + _ => Ok("00000000000000000000000000000000".into()), } } @@ -293,6 +294,7 @@ impl BlockInProgress { Self::safe_store_get_hash(host, Some(EVM_TRANSACTIONS_RECEIPTS))?; let transactions_root = Self::safe_store_get_hash(host, Some(EVM_TRANSACTIONS_OBJECTS))?; + let base_fee_per_gas = base_fee_per_gas(host, self.timestamp); let new_block = L2Block::new( self.number, self.valid_txs, @@ -304,6 +306,7 @@ impl BlockInProgress { receipts_root, self.cumulative_gas, block_constants.gas_limit, + base_fee_per_gas, ); storage::store_current_block(host, &new_block) .context("Failed to store the current block")?; diff --git a/etherlink/kernel_evm/kernel/src/simulation.rs b/etherlink/kernel_evm/kernel/src/simulation.rs index 921c7ffabdba..8839ec1cc2d6 100644 --- a/etherlink/kernel_evm/kernel/src/simulation.rs +++ b/etherlink/kernel_evm/kernel/src/simulation.rs @@ -609,6 +609,12 @@ fn parse_inbox(host: &mut Host) -> Result { impl VersionedEncoding for SimulationResult { const VERSION: u8 = SIMULATION_ENCODING_VERSION; + fn unversionned_encode(&self) -> bytes::BytesMut { + self.rlp_bytes() + } + fn unversionned_decode(decoder: &Rlp) -> Result { + Self::decode(decoder) + } } pub fn start_simulation_mode( diff --git a/etherlink/kernel_evm/kernel/src/storage.rs b/etherlink/kernel_evm/kernel/src/storage.rs index 0304e9c0b84a..7b5cf79e3554 100644 --- a/etherlink/kernel_evm/kernel/src/storage.rs +++ b/etherlink/kernel_evm/kernel/src/storage.rs @@ -256,8 +256,9 @@ pub fn read_optional_rlp( pub fn read_current_block(host: &mut Host) -> Result { let hash = read_current_block_hash(host)?; let block_path = block_path(hash)?; - let block = read_rlp(host, &block_path)?; - Ok(block) + let bytes = &host.store_read_all(&block_path)?; + let block_from_bytes = L2Block::from_bytes(bytes)?; + Ok(block_from_bytes) } fn store_current_block_number_and_hash( @@ -282,7 +283,9 @@ fn store_block( ) -> Result<(), Error> { let mut index = init_blocks_index()?; index_block(host, &block.hash, &mut index)?; - store_rlp(block, host, block_path) + let bytes = block.to_bytes(); + host.store_write_all(block_path, &bytes) + .map_err(Error::from) } pub fn store_block_by_hash( diff --git a/etherlink/tezt/lib/block.ml b/etherlink/tezt/lib/block.ml index f52df7d7cb6b..7d85ac1437c9 100644 --- a/etherlink/tezt/lib/block.ml +++ b/etherlink/tezt/lib/block.ml @@ -48,6 +48,8 @@ type t = { timestamp : int32; transactions : transactions; uncles : string list; + baseFeePerGas : int64; + mixHash : string; } let parse_transactions json = @@ -73,6 +75,11 @@ let of_json json = let res = json |-> field in if JSON.is_null res then json |-> alternative else res in + + let ( ||-> ) json (field, default, decoder) = + let res = json |-> field in + if JSON.is_null res then default else res |> decoder + in { number = json |-> "number" |> as_int32; hash = json |-> "hash" |> as_string; @@ -94,4 +101,10 @@ let of_json json = timestamp = json |-> "timestamp" |> as_int32; transactions = json |-> "transactions" |> parse_transactions; uncles = json |-> "uncles" |> as_list |> List.map as_string; + baseFeePerGas = json ||-> ("baseFeePerGas", 1000000000L, as_int64); + mixHash = + json + ||-> ( "mixHash", + "0x0000000000000000000000000000000000000000000000000000000000000000", + as_string ); } diff --git a/etherlink/tezt/lib/block.mli b/etherlink/tezt/lib/block.mli index f0282b78f9c0..3a9ce1e5b93d 100644 --- a/etherlink/tezt/lib/block.mli +++ b/etherlink/tezt/lib/block.mli @@ -52,6 +52,8 @@ type t = { timestamp : int32; transactions : transactions; uncles : string list; + baseFeePerGas : int64; + mixHash : string; } (** Extracts a block {!t} from a JSON. *) -- GitLab From e69a7a2a98941fd31769fecef012644524265d9b Mon Sep 17 00:00:00 2001 From: Hantang Sun Date: Fri, 10 May 2024 22:31:59 +0800 Subject: [PATCH 2/3] Etherlink: Tezt for getBlockBy* RPC --- etherlink/tezt/tests/evm_rollup.ml | 40 +++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/etherlink/tezt/tests/evm_rollup.ml b/etherlink/tezt/tests/evm_rollup.ml index a8796285a333..10a95d449bca 100644 --- a/etherlink/tezt/tests/evm_rollup.ml +++ b/etherlink/tezt/tests/evm_rollup.ml @@ -757,6 +757,7 @@ let test_rpc_getBlockByHash = register_both ~tags:["evm"; "rpc"; "get_block_by_hash"] ~title:"RPC method eth_getBlockByHash" + ~minimum_base_fee_per_gas:base_fee_for_hardcoded_tx @@ fun ~protocol:_ ~evm_setup -> let evm_node_endpoint = Evm_node.endpoint evm_setup.evm_node in let* block = Eth_cli.get_block ~block_id:"0" ~endpoint:evm_node_endpoint in @@ -806,6 +807,42 @@ let test_rpc_getBlockReceipts = assert (List.equal ( = ) txs expected_txs) ; unit +let test_rpc_getBlockBy_return_base_fee_per_gas_and_mix_hash = + register_both + ~tags:["evm"; "rpc"; "get_block_by_hash"] + ~title:"getBlockBy returns base fee per gas and mix hash" + ~minimum_base_fee_per_gas:(Wei.to_wei_z @@ Z.of_int 100) + @@ fun ~protocol:_ ~evm_setup -> + let evm_node_endpoint = Evm_node.endpoint evm_setup.evm_node in + + let* _ = + send + ~sender:Eth_account.bootstrap_accounts.(0) + ~receiver:Eth_account.bootstrap_accounts.(1) + ~value:Wei.one + evm_setup + in + let* block_by_number = + Eth_cli.get_block ~block_id:"1" ~endpoint:evm_node_endpoint + in + Check.((block_by_number.baseFeePerGas = 100L) int64) + ~error_msg:"Unexpected block number, should be %%R, but got %%L" ; + Check.( + (block_by_number.mixHash + = "0x0000000000000000000000000000000000000000000000000000000000000000") + string) + ~error_msg:"Unexpected mix hash, should be %%R, but got %%L" ; + + let* block_by_hash = get_block_by_hash evm_setup block_by_number.hash in + Check.((block_by_hash.baseFeePerGas = 100L) int64) + ~error_msg:"Unexpected block number, should be %%R, but got %%L" ; + Check.( + (block_by_hash.mixHash + = "0x0000000000000000000000000000000000000000000000000000000000000000") + string) + ~error_msg:"Unexpected mix hash, should be %%R, but got %%L" ; + unit + let test_l2_block_size_non_zero = register_both ~tags:["evm"; "block"; "size"] @@ -5804,7 +5841,8 @@ let register_evm_node ~protocols = test_rpc_maxPriorityFeePerGas protocols ; test_proxy_read_only protocols ; test_unsupported_rpc protocols ; - test_validation_with_legacy_encoding protocols + test_validation_with_legacy_encoding protocols ; + test_rpc_getBlockBy_return_base_fee_per_gas_and_mix_hash protocols let protocols = Protocol.all -- GitLab From 3b2c55ccb40db868b1f7624001eeb7dbf3327ec8 Mon Sep 17 00:00:00 2001 From: pecornilleau Date: Thu, 23 May 2024 10:12:46 +0200 Subject: [PATCH 3/3] Etherlink: changelog 13159 --- etherlink/CHANGES_KERNEL.md | 3 +++ etherlink/CHANGES_NODE.md | 2 ++ 2 files changed, 5 insertions(+) diff --git a/etherlink/CHANGES_KERNEL.md b/etherlink/CHANGES_KERNEL.md index 9bcb1674e852..c43b194a3b22 100644 --- a/etherlink/CHANGES_KERNEL.md +++ b/etherlink/CHANGES_KERNEL.md @@ -14,6 +14,9 @@ - Validation returns the transaction object instead of the address of the sender. (!12873, !13292) +- Introduce new block encoding to include `baseFeePerGas` and `mixHash`. + New blocks would contain `baseFeePerGas` and a default `mixHash`. (!13159) + ### Internal - Gas price is removed from internal structure block in progress. (!13220) diff --git a/etherlink/CHANGES_NODE.md b/etherlink/CHANGES_NODE.md index 48b7c860328c..a6c9761bdc9f 100644 --- a/etherlink/CHANGES_NODE.md +++ b/etherlink/CHANGES_NODE.md @@ -32,6 +32,8 @@ pool is not supported. (!13162) - Support `debug_traceTransaction` with its default logger `structLogs`. (!13268, !13321, !13350, !13378) +- Return `baseFeePerGas` and `mixHash` field for `eth_getBlockBy*` RPCs. The + former only when appropriate, the later with a default value. (!13159) ### Experimental -- GitLab