Skip to content
97 changes: 95 additions & 2 deletions crates/core/src/types/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ use super::{
GAS_LIMIT_MINIMUM,
};
use crate::{
rlp::{encode::RLPEncode, structs::Encoder},
rlp::{
decode::RLPDecode,
encode::RLPEncode,
structs::{Decoder, Encoder},
},
types::Receipt,
Address, H256, U256,
};
Expand Down Expand Up @@ -78,6 +82,59 @@ impl RLPEncode for BlockHeader {
}
}

impl RLPDecode for BlockHeader {
fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), crate::rlp::error::RLPDecodeError> {
let decoder = Decoder::new(rlp)?;
let (parent_hash, decoder) = decoder.decode_field("parent_hash")?;
let (ommers_hash, decoder) = decoder.decode_field("ommers_hash")?;
let (coinbase, decoder) = decoder.decode_field("coinbase")?;
let (state_root, decoder) = decoder.decode_field("state_root")?;
let (transactions_root, decoder) = decoder.decode_field("transactions_root")?;
let (receipt_root, decoder) = decoder.decode_field("receipt_root")?;
let (logs_bloom, decoder) = decoder.decode_field("logs_bloom")?;
let (difficulty, decoder) = decoder.decode_field("difficulty")?;
let (number, decoder) = decoder.decode_field("number")?;
let (gas_limit, decoder) = decoder.decode_field("gas_limit")?;
let (gas_used, decoder) = decoder.decode_field("gas_used")?;
let (timestamp, decoder) = decoder.decode_field("timestamp")?;
let (extra_data, decoder) = decoder.decode_field("extra_data")?;
let (prev_randao, decoder) = decoder.decode_field("prev_randao")?;
let (nonce, decoder) = decoder.decode_field("nonce")?;
let nonce = u64::from_be_bytes(nonce);
let (base_fee_per_gas, decoder) = decoder.decode_field("base_fee_per_gas")?;
let (withdrawals_root, decoder) = decoder.decode_field("withdrawals_root")?;
let (blob_gas_used, decoder) = decoder.decode_field("blob_gas_used")?;
let (excess_blob_gas, decoder) = decoder.decode_field("excess_blob_gas")?;
let (parent_beacon_block_root, decoder) =
decoder.decode_field("parent_beacon_block_root")?;
Ok((
BlockHeader {
parent_hash,
ommers_hash,
coinbase,
state_root,
transactions_root,
receipt_root,
logs_bloom,
difficulty,
number,
gas_limit,
gas_used,
timestamp,
extra_data,
prev_randao,
nonce,
base_fee_per_gas,
withdrawals_root,
blob_gas_used,
excess_blob_gas,
parent_beacon_block_root,
},
decoder.finish()?,
))
}
}

// The body of a block on the chain
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct BlockBody {
Expand Down Expand Up @@ -109,7 +166,7 @@ impl BlockBody {
// Value: tx_type || RLP(tx) if tx_type != 0
// RLP(tx) else
let mut v = Vec::new();
tx.encode_with_type(&mut v);
tx.encode(&mut v);

(k, v)
})
Expand Down Expand Up @@ -171,6 +228,23 @@ impl RLPEncode for BlockBody {
}
}

impl RLPDecode for BlockBody {
fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), crate::rlp::error::RLPDecodeError> {
let decoder = Decoder::new(rlp)?;
let (transactions, decoder) = decoder.decode_field("transactions")?;
let (ommers, decoder) = decoder.decode_field("ommers")?;
let (withdrawals, decoder) = decoder.decode_field("withdrawals")?;
Ok((
BlockBody {
transactions,
ommers,
withdrawals,
},
decoder.finish()?,
))
}
}

impl BlockHeader {
pub fn compute_block_hash(&self) -> H256 {
let mut buf = vec![];
Expand Down Expand Up @@ -201,6 +275,25 @@ impl RLPEncode for Withdrawal {
}
}

impl RLPDecode for Withdrawal {
fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), crate::rlp::error::RLPDecodeError> {
let decoder = Decoder::new(rlp)?;
let (index, decoder) = decoder.decode_field("index")?;
let (validator_index, decoder) = decoder.decode_field("validator_index")?;
let (address, decoder) = decoder.decode_field("address")?;
let (amount, decoder) = decoder.decode_field("amount")?;
Ok((
Withdrawal {
index,
validator_index,
address,
amount,
},
decoder.finish()?,
))
}
}

// Checks that the gas_limit fits the gas bounds set by its parent block
fn check_gas_limit(gas_limit: u64, parent_gas_limit: u64) -> bool {
let max_adjustment_delta = parent_gas_limit / GAS_LIMIT_ADJUSTMENT_FACTOR;
Expand Down
33 changes: 2 additions & 31 deletions crates/core/src/types/engine/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ use crate::rlp::decode::RLPDecode;
use crate::{rlp::error::RLPDecodeError, serde_utils};

use crate::types::{
compute_withdrawals_root, BlockBody, BlockHeader, EIP1559Transaction, EIP2930Transaction,
EIP4844Transaction, LegacyTransaction, Transaction, Withdrawal, DEFAULT_OMMERS_HASH,
compute_withdrawals_root, BlockBody, BlockHeader, Transaction, Withdrawal, DEFAULT_OMMERS_HASH,
};

#[allow(unused)]
Expand Down Expand Up @@ -64,35 +63,7 @@ impl EncodedTransaction {
/// A) `TransactionType || Transaction` (Where Transaction type is an 8-bit number between 0 and 0x7f, and Transaction is an rlp encoded transaction of type TransactionType)
/// B) `LegacyTransaction` (An rlp encoded LegacyTransaction)
fn decode(&self) -> Result<Transaction, RLPDecodeError> {
// Look at the first byte to check if it corresponds to a TransactionType
match self.0.first() {
// First byte is a valid TransactionType
Some(tx_type) if *tx_type < 0x7f => {
// Decode tx based on type
let tx_bytes = &self.0.as_ref()[1..];
match *tx_type {
// Legacy
0x0 => LegacyTransaction::decode(tx_bytes).map(Transaction::LegacyTransaction), // TODO: check if this is a real case scenario
// EIP2930
0x1 => {
EIP2930Transaction::decode(tx_bytes).map(Transaction::EIP2930Transaction)
}
// EIP1559
0x2 => {
EIP1559Transaction::decode(tx_bytes).map(Transaction::EIP1559Transaction)
}
// EIP4844
0x3 => {
EIP4844Transaction::decode(tx_bytes).map(Transaction::EIP4844Transaction)
}
ty => Err(RLPDecodeError::Custom(format!(
"Invalid transaction type: {ty}"
))),
}
}
// LegacyTransaction
_ => LegacyTransaction::decode(self.0.as_ref()).map(Transaction::LegacyTransaction),
}
Transaction::decode(self.0.as_ref())
}
}

Expand Down
58 changes: 46 additions & 12 deletions crates/core/src/types/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,6 @@ pub enum TxType {
}

impl Transaction {
pub fn encode_with_type(&self, buf: &mut dyn bytes::BufMut) {
// tx_type || RLP(tx) if tx_type != 0
// RLP(tx) else
match self {
// Legacy transactions don't have a prefix
Transaction::LegacyTransaction(_) => {}
_ => buf.put_u8(self.tx_type() as u8),
}

self.encode(buf);
}

pub fn tx_type(&self) -> TxType {
match self {
Transaction::LegacyTransaction(_) => TxType::Legacy,
Expand All @@ -115,7 +103,16 @@ impl Transaction {
}

impl RLPEncode for Transaction {
/// Based on [EIP-2718]
/// Transactions can be encoded in the following formats:
/// A) `TransactionType || Transaction` (Where Transaction type is an 8-bit number between 0 and 0x7f, and Transaction is an rlp encoded transaction of type TransactionType)
/// B) `LegacyTransaction` (An rlp encoded LegacyTransaction)
fn encode(&self, buf: &mut dyn bytes::BufMut) {
match self {
// Legacy transactions don't have a prefix
Transaction::LegacyTransaction(_) => {}
_ => buf.put_u8(self.tx_type() as u8),
}
match self {
Transaction::LegacyTransaction(t) => t.encode(buf),
Transaction::EIP2930Transaction(t) => t.encode(buf),
Expand All @@ -125,6 +122,43 @@ impl RLPEncode for Transaction {
}
}

impl RLPDecode for Transaction {
/// Based on [EIP-2718]
/// Transactions can be encoded in the following formats:
/// A) `TransactionType || Transaction` (Where Transaction type is an 8-bit number between 0 and 0x7f, and Transaction is an rlp encoded transaction of type TransactionType)
/// B) `LegacyTransaction` (An rlp encoded LegacyTransaction)
fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> {
// Look at the first byte to check if it corresponds to a TransactionType
match rlp.first() {
// First byte is a valid TransactionType
Some(tx_type) if *tx_type < 0x7f => {
// Decode tx based on type
let tx_bytes = &rlp[1..];
match *tx_type {
// Legacy
0x0 => LegacyTransaction::decode_unfinished(tx_bytes)
.map(|(tx, rem)| (Transaction::LegacyTransaction(tx), rem)), // TODO: check if this is a real case scenario
// EIP2930
0x1 => EIP2930Transaction::decode_unfinished(tx_bytes)
.map(|(tx, rem)| (Transaction::EIP2930Transaction(tx), rem)),
// EIP1559
0x2 => EIP1559Transaction::decode_unfinished(tx_bytes)
.map(|(tx, rem)| (Transaction::EIP1559Transaction(tx), rem)),
// EIP4844
0x3 => EIP4844Transaction::decode_unfinished(tx_bytes)
.map(|(tx, rem)| (Transaction::EIP4844Transaction(tx), rem)),
ty => Err(RLPDecodeError::Custom(format!(
"Invalid transaction type: {ty}"
))),
}
}
// LegacyTransaction
_ => LegacyTransaction::decode_unfinished(rlp)
.map(|(tx, rem)| (Transaction::LegacyTransaction(tx), rem)),
}
}
}

/// The transaction's kind: call or create.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum TxKind {
Expand Down
35 changes: 30 additions & 5 deletions crates/storage/src/in_memory.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
use super::{Key, StoreEngine, Value};
use crate::error::StoreError;
use ethereum_rust_core::types::AccountInfo;
use ethereum_rust_core::types::{AccountInfo, BlockBody, BlockHeader, BlockNumber};
use ethereum_types::Address;
use std::{collections::HashMap, fmt::Debug};

#[derive(Default)]
pub struct Store {
account_infos: HashMap<Address, AccountInfo>,
bodies: HashMap<BlockNumber, BlockBody>,
headers: HashMap<BlockNumber, BlockHeader>,
values: HashMap<Key, Value>,
}

impl Store {
pub fn new() -> Result<Self, StoreError> {
Ok(Self {
account_infos: HashMap::new(),
values: HashMap::new(),
})
Ok(Self::default())
}
}

Expand All @@ -41,6 +40,32 @@ impl StoreEngine for Store {
fn get_value(&self, key: Key) -> Result<Option<Vec<u8>>, StoreError> {
Ok(self.values.get(&key).cloned())
}

fn get_block_header(&self, block_number: u64) -> Result<Option<BlockHeader>, StoreError> {
Ok(self.headers.get(&block_number).cloned())
}

fn get_block_body(&self, block_number: u64) -> Result<Option<BlockBody>, StoreError> {
Ok(self.bodies.get(&block_number).cloned())
}

fn add_block_header(
&mut self,
block_number: BlockNumber,
block_header: BlockHeader,
) -> Result<(), StoreError> {
self.headers.insert(block_number, block_header);
Ok(())
}

fn add_block_body(
&mut self,
block_number: BlockNumber,
block_body: BlockBody,
) -> Result<(), StoreError> {
self.bodies.insert(block_number, block_body);
Ok(())
}
}

impl Debug for Store {
Expand Down
Loading