diff --git a/src/kernel_evm_mockup/src/account.rs b/src/kernel_evm_mockup/src/account.rs index edd304e315c5223ec2f405f73f3fed3e1110c88f..ab8379f302dce30e5c563be19e6ee01bd3a2ec2c 100644 --- a/src/kernel_evm_mockup/src/account.rs +++ b/src/kernel_evm_mockup/src/account.rs @@ -2,17 +2,14 @@ // // SPDX-License-Identifier: MIT +use crate::eth_gen::{OwnedHash, Quantity}; use crate::wei::Wei; -pub type OwnedHash = Vec; - -pub type Hash<'a> = &'a Vec; - // Simple representation of an account, only contains fixed-sized values (no // code nor storage). pub struct Account { pub hash: OwnedHash, - pub nonce: u64, // initially 0, updated after each transaction + pub nonce: Quantity, // initially 0, updated after each transaction pub balance: Wei, pub code_hash: OwnedHash, // 256 bits hash } diff --git a/src/kernel_evm_mockup/src/block.rs b/src/kernel_evm_mockup/src/block.rs new file mode 100644 index 0000000000000000000000000000000000000000..812463cf37734cb76a896fbc7f1f21874692cf5b --- /dev/null +++ b/src/kernel_evm_mockup/src/block.rs @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2023 Nomadic Labs +// +// SPDX-License-Identifier: MIT + +use crate::eth_gen::{L2Level, OwnedHash, Quantity, RawTransactions}; + +pub struct L2Block { + // This choice of a L2 block representation is totally + // arbitrarily based on what is an Ethereum block and is + // subject to change. + pub number: L2Level, + pub hash: OwnedHash, // 32 bytes + pub parent_hash: OwnedHash, + pub nonce: Quantity, + pub sha3_uncles: OwnedHash, + pub logs_bloom: Option, + pub transactions_root: OwnedHash, + pub state_root: OwnedHash, + pub receipts_root: OwnedHash, + pub miner: OwnedHash, + pub difficulty: Quantity, + pub total_difficulty: Quantity, + pub extra_data: OwnedHash, + pub size: Quantity, + pub gas_limit: Quantity, + pub gas_used: Quantity, + pub timestamp: Quantity, + pub transactions: RawTransactions, + pub uncles: Vec, +} + +impl L2Block { + // dead code is allowed in this implementation because the following constants + // are not used outside the scope of L2Block + #![allow(dead_code)] + + const DUMMY_QUANTITY: Quantity = 0; + const DUMMY_HASH: &str = "0000000000000000000000000000000000000000"; + + fn dummy_hash() -> OwnedHash { + L2Block::DUMMY_HASH.into() + } + + pub fn new(number: L2Level, hash: OwnedHash, transactions: RawTransactions) -> Self { + L2Block { + number, + hash, + parent_hash: L2Block::dummy_hash(), + nonce: L2Block::DUMMY_QUANTITY, + sha3_uncles: L2Block::dummy_hash(), + logs_bloom: None, + transactions_root: L2Block::dummy_hash(), + state_root: L2Block::dummy_hash(), + receipts_root: L2Block::dummy_hash(), + miner: L2Block::dummy_hash(), + difficulty: L2Block::DUMMY_QUANTITY, + total_difficulty: L2Block::DUMMY_QUANTITY, + extra_data: L2Block::dummy_hash(), + size: L2Block::DUMMY_QUANTITY, + gas_limit: L2Block::DUMMY_QUANTITY, + gas_used: L2Block::DUMMY_QUANTITY, + timestamp: L2Block::DUMMY_QUANTITY, + transactions, + uncles: Vec::new(), + } + } +} diff --git a/src/kernel_evm_mockup/src/eth_gen.rs b/src/kernel_evm_mockup/src/eth_gen.rs new file mode 100644 index 0000000000000000000000000000000000000000..766bed10558fdbb85303e56a0f7a8b3eb27b1d58 --- /dev/null +++ b/src/kernel_evm_mockup/src/eth_gen.rs @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: 2023 Nomadic Labs +// +// SPDX-License-Identifier: MIT + +pub type RawTransaction = Vec; +pub type RawTransactions = Vec; +pub type L2Level = u64; +pub type Quantity = u64; +pub type OwnedHash = Vec; +pub type Hash<'a> = &'a Vec; diff --git a/src/kernel_evm_mockup/src/inbox.rs b/src/kernel_evm_mockup/src/inbox.rs index 657e458f91fc3519c2a8fe83875f0df7a7610e65..afe5ecc54a4322febed4082b6444574cd961c510 100644 --- a/src/kernel_evm_mockup/src/inbox.rs +++ b/src/kernel_evm_mockup/src/inbox.rs @@ -9,9 +9,11 @@ use host::input::Message; use host::rollup_core::RawRollupCore; use host::runtime::Runtime; +use crate::eth_gen::RawTransaction; + pub struct Transaction { pub level: i32, - pub tx: Vec, + pub tx: RawTransaction, } pub enum Error { diff --git a/src/kernel_evm_mockup/src/lib.rs b/src/kernel_evm_mockup/src/lib.rs index c1d5438f1429a8569f6a10ed2c46aa58658f24bd..053c037c8b36dcab7027d8e6286f4684a0fbb490 100644 --- a/src/kernel_evm_mockup/src/lib.rs +++ b/src/kernel_evm_mockup/src/lib.rs @@ -15,8 +15,10 @@ use crate::storage::store_account; use crate::wei::{from_eth, Wei}; mod account; +mod block; mod blueprint; mod error; +mod eth_gen; mod inbox; mod storage; mod wei; diff --git a/src/kernel_evm_mockup/src/storage.rs b/src/kernel_evm_mockup/src/storage.rs index 38219c5ec68ea72cc41d32e440082737358f2365..ef6d0fb2352dfce73684c584cb48a1de4bb212ef 100644 --- a/src/kernel_evm_mockup/src/storage.rs +++ b/src/kernel_evm_mockup/src/storage.rs @@ -10,7 +10,9 @@ use host::runtime::{load_value_slice, Runtime}; use std::str::from_utf8; use crate::account::*; +use crate::block::L2Block; use crate::error::Error; +use crate::eth_gen::{Hash, L2Level, RawTransactions}; use crate::wei::Wei; use primitive_types::U256; @@ -21,6 +23,12 @@ const EVM_ACCOUNT_BALANCE: RefPath = RefPath::assert_from(b"/balance"); const EVM_ACCOUNT_NONCE: RefPath = RefPath::assert_from(b"/nonce"); const EVM_ACCOUNT_CODE_HASH: RefPath = RefPath::assert_from(b"/code_hash"); +const EVM_CURRENT_BLOCK: RefPath = RefPath::assert_from(b"/evm/blocks/current"); +const EVM_BLOCKS: RefPath = RefPath::assert_from(b"/evm/blocks"); +const EVM_BLOCKS_NUMBER: RefPath = RefPath::assert_from(b"/number"); +const EVM_BLOCKS_HASH: RefPath = RefPath::assert_from(b"/hash"); +const EVM_BLOCKS_TRANSACTIONS: RefPath = RefPath::assert_from(b"/transactions"); + const CODE_HASH_SIZE: usize = 32; /// The size of one 256 bit word. Size in bytes @@ -38,17 +46,24 @@ fn write_u256(host: &mut impl Runtime, path: &OwnedPath, value: U256) -> Result< host.store_write(path, &bytes, 0).map_err(Error::from) } -pub fn address_path(address: Hash) -> Result { +fn address_path(address: Hash) -> Result { let address: &str = from_utf8(address)?; let address_path: Vec = format!("/{}", &address).into(); OwnedPath::try_from(address_path).map_err(Error::from) } -pub fn account_path(address: Hash) -> Result { +fn account_path(address: Hash) -> Result { let address_hash = address_path(address)?; concat(&EVM_ACCOUNTS, &address_hash).map_err(Error::from) } +fn block_path(number: L2Level) -> Result { + let number: &str = &number.to_string(); + let raw_number_path: Vec = format!("/{}", &number).into(); + let number_path = OwnedPath::try_from(raw_number_path).map_err(Error::from)?; + concat(&EVM_BLOCKS, &number_path).map_err(Error::from) +} + pub fn read_account_nonce( host: &mut Host, account_path: &OwnedPath, @@ -96,7 +111,7 @@ pub fn read_account( }) } -pub fn store_nonce( +fn store_nonce( host: &mut Host, account_path: &OwnedPath, nonce: u64, @@ -106,7 +121,7 @@ pub fn store_nonce( .map_err(Error::from) } -pub fn store_balance( +fn store_balance( host: &mut Host, account_path: &OwnedPath, balance: Wei, @@ -115,7 +130,7 @@ pub fn store_balance( write_u256(host, &path, balance) } -pub fn store_code_hash( +fn store_code_hash( host: &mut Host, account_path: &OwnedPath, code_hash: Hash, @@ -133,3 +148,63 @@ pub fn store_account( store_balance(host, &account_path, account.balance)?; store_code_hash(host, &account_path, &account.code_hash) } + +fn store_block_number( + host: &mut Host, + block_path: &OwnedPath, + block_number: L2Level, +) -> Result<(), Error> { + let path = concat(block_path, &EVM_BLOCKS_NUMBER)?; + host.store_write(&path, &u64::to_le_bytes(block_number), 0) + .map_err(Error::from) +} + +fn store_block_hash( + host: &mut Host, + block_path: &OwnedPath, + block_hash: Hash, +) -> Result<(), Error> { + let path = concat(block_path, &EVM_BLOCKS_HASH)?; + host.store_write(&path, block_hash, 0).map_err(Error::from) +} + +fn store_block_transactions( + host: &mut Host, + block_path: &OwnedPath, + block_transactions: &RawTransactions, +) -> Result<(), Error> { + let path = concat(block_path, &EVM_BLOCKS_TRANSACTIONS)?; + /* For now, to keep it simple we made the assumption that ONE BLOCK = ONE TRANSACTION, + this is why the following code make sense in this case: */ + let transaction = &block_transactions[0]; + host.store_write(&path, transaction, 0).map_err(Error::from) +} + +fn store_block( + host: &mut Host, + block: &L2Block, + block_path: OwnedPath, +) -> Result<(), Error> { + store_block_number(host, &block_path, block.number)?; + store_block_hash(host, &block_path, &block.hash)?; + store_block_transactions(host, &block_path, &block.transactions) +} + +pub fn store_block_by_number( + host: &mut Host, + block: &L2Block, +) -> Result<(), Error> { + let block_path = block_path(block.number)?; + store_block(host, block, block_path) +} + +pub fn store_current_block( + host: &mut Host, + block: L2Block, +) -> Result<(), Error> { + let current_block_path = OwnedPath::from(EVM_CURRENT_BLOCK); + store_block(host, &block, current_block_path)?; + /* When storing the current block's infos we need to store it under the [evm/blocks/] + path as well, thus the following line: */ + store_block_by_number(host, &block) +}