Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions crates/blockchain/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ use ethrex_common::types::fee_config::FeeConfig;
use ethrex_common::types::requests::{EncodedRequests, Requests, compute_requests_hash};
use ethrex_common::types::{
AccountState, AccountUpdate, Block, BlockHash, BlockHeader, BlockNumber, ChainConfig, Code,
EIP4844Transaction, Receipt, Transaction, WrappedEIP4844Transaction, compute_receipts_root,
validate_block_header, validate_cancun_header_fields, validate_prague_header_fields,
validate_pre_cancun_header_fields,
EIP4844Transaction, Fork, Receipt, Transaction, WrappedEIP4844Transaction,
compute_receipts_root, validate_block_header, validate_cancun_header_fields,
validate_prague_header_fields, validate_pre_cancun_header_fields,
};
use ethrex_common::types::{ELASTICITY_MULTIPLIER, P2PTransaction};
use ethrex_common::types::{Fork, MempoolTransaction};
use ethrex_common::types::{Fork::*, MempoolTransaction};
use ethrex_common::{Address, H256, TrieLogger};
use ethrex_metrics::metrics;
use ethrex_rlp::decode::RLPDecode;
Expand Down Expand Up @@ -1263,7 +1263,7 @@ impl Blockchain {
// NOTE: We could add a tx size limit here, but it's not in the actual spec

// Check init code size
if config.is_shanghai_activated(header.timestamp)
if config.is_fork_activated(Shanghai, header.timestamp)
&& tx.is_contract_creation()
&& tx.data().len() > MAX_INITCODE_SIZE as usize
{
Expand All @@ -1274,7 +1274,8 @@ impl Blockchain {
return Err(MempoolError::TxMaxDataSizeError);
}

if config.is_osaka_activated(header.timestamp) && tx.gas_limit() > POST_OSAKA_GAS_LIMIT_CAP
if config.is_fork_activated(Osaka, header.timestamp)
&& tx.gas_limit() > POST_OSAKA_GAS_LIMIT_CAP
{
// https://eips.ethereum.org/EIPS/eip-7825
return Err(MempoolError::TxMaxGasLimitExceededError(
Expand Down Expand Up @@ -1430,7 +1431,7 @@ pub fn validate_requests_hash(
chain_config: &ChainConfig,
requests: &[Requests],
) -> Result<(), ChainError> {
if !chain_config.is_prague_activated(header.timestamp) {
if !chain_config.is_fork_activated(Prague, header.timestamp) {
return Ok(());
}

Expand Down Expand Up @@ -1517,7 +1518,7 @@ pub fn validate_block(
validate_block_header(&block.header, parent_header, elasticity_multiplier)
.map_err(InvalidBlockError::from)?;

if chain_config.is_osaka_activated(block.header.timestamp) {
if chain_config.is_fork_activated(Osaka, block.header.timestamp) {
let block_rlp_size = block.encode_to_vec().len();
if block_rlp_size > MAX_RLP_BLOCK_SIZE as usize {
return Err(error::ChainError::InvalidBlock(
Expand All @@ -1528,14 +1529,14 @@ pub fn validate_block(
));
}
}
if chain_config.is_prague_activated(block.header.timestamp) {
if chain_config.is_fork_activated(Prague, block.header.timestamp) {
validate_prague_header_fields(&block.header, parent_header, chain_config)
.map_err(InvalidBlockError::from)?;
verify_blob_gas_usage(block, chain_config)?;
if chain_config.is_osaka_activated(block.header.timestamp) {
if chain_config.is_fork_activated(Osaka, block.header.timestamp) {
verify_transaction_max_gas_limit(block)?;
}
} else if chain_config.is_cancun_activated(block.header.timestamp) {
} else if chain_config.is_fork_activated(Cancun, block.header.timestamp) {
validate_cancun_header_fields(&block.header, parent_header, chain_config)
.map_err(InvalidBlockError::from)?;
verify_blob_gas_usage(block, chain_config)?;
Expand Down
5 changes: 1 addition & 4 deletions crates/blockchain/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ pub const TX_ACCESS_LIST_ADDRESS_GAS: u64 = 2400;
// Gas cost for each storage key specified on access lists
pub const TX_ACCESS_LIST_STORAGE_KEY_GAS: u64 = 1900;

// Gas cost for each non zero byte on transaction data
pub const TX_DATA_NON_ZERO_GAS: u64 = 68;

// === EIP-170 constants ===

// Max bytecode size
Expand All @@ -37,7 +34,7 @@ pub const MAX_TRANSACTION_DATA_SIZE: u32 = 4 * 32 * 1024; // 128 Kb
// === EIP-2028 constants ===

// Gas cost for each non zero byte on transaction data
pub const TX_DATA_NON_ZERO_GAS_EIP2028: u64 = 16;
pub const TX_DATA_NON_ZERO_GAS: u64 = 16;

// === EIP-4844 constants ===

Expand Down
79 changes: 25 additions & 54 deletions crates/blockchain/mempool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ use std::{
use crate::{
constants::{
TX_ACCESS_LIST_ADDRESS_GAS, TX_ACCESS_LIST_STORAGE_KEY_GAS, TX_CREATE_GAS_COST,
TX_DATA_NON_ZERO_GAS, TX_DATA_NON_ZERO_GAS_EIP2028, TX_DATA_ZERO_GAS_COST, TX_GAS_COST,
TX_INIT_CODE_WORD_GAS_COST,
TX_DATA_NON_ZERO_GAS, TX_DATA_ZERO_GAS_COST, TX_GAS_COST, TX_INIT_CODE_WORD_GAS_COST,
},
error::MempoolError,
};
use ethrex_common::{
Address, H160, H256, U256,
types::{BlobsBundle, BlockHeader, ChainConfig, MempoolTransaction, Transaction, TxType},
types::{
BlobsBundle, BlockHeader, ChainConfig, Fork::*, MempoolTransaction, Transaction, TxType,
},
};
use ethrex_storage::error::StoreError;
use std::collections::HashSet;
Expand Down Expand Up @@ -426,11 +427,7 @@ pub fn transaction_intrinsic_gas(
let data_len = tx.data().len() as u64;

if data_len > 0 {
let non_zero_gas_cost = if config.is_istanbul_activated(header.number) {
TX_DATA_NON_ZERO_GAS_EIP2028
} else {
TX_DATA_NON_ZERO_GAS
};
let non_zero_gas_cost = TX_DATA_NON_ZERO_GAS;

let non_zero_count = tx.data().iter().filter(|&&x| x != 0u8).count() as u64;

Expand All @@ -444,7 +441,7 @@ pub fn transaction_intrinsic_gas(
.checked_add(zero_count * TX_DATA_ZERO_GAS_COST)
.ok_or(MempoolError::TxGasOverflowError)?;

if is_contract_creation && config.is_shanghai_activated(header.timestamp) {
if is_contract_creation && config.is_fork_activated(Shanghai, header.timestamp) {
// Len in 32 bytes sized words
let len_in_words = data_len.saturating_add(31) / 32;

Expand Down Expand Up @@ -477,8 +474,7 @@ mod tests {
use crate::error::MempoolError;
use crate::mempool::{
Mempool, TX_ACCESS_LIST_ADDRESS_GAS, TX_ACCESS_LIST_STORAGE_KEY_GAS, TX_CREATE_GAS_COST,
TX_DATA_NON_ZERO_GAS, TX_DATA_NON_ZERO_GAS_EIP2028, TX_DATA_ZERO_GAS_COST, TX_GAS_COST,
TX_INIT_CODE_WORD_GAS_COST,
TX_DATA_NON_ZERO_GAS, TX_DATA_ZERO_GAS_COST, TX_GAS_COST, TX_INIT_CODE_WORD_GAS_COST,
};
use std::collections::HashMap;

Expand All @@ -487,7 +483,7 @@ mod tests {
BYTES_PER_BLOB, BlobsBundle, BlockHeader, ChainConfig, EIP1559Transaction,
EIP4844Transaction, MempoolTransaction, Transaction, TxKind,
};
use ethrex_common::{Address, Bytes, H256, U256};
use ethrex_common::{Address, Bytes, H256, U256, types::Fork::*};
use ethrex_storage::EngineType;
use ethrex_storage::{Store, error::StoreError};

Expand All @@ -505,13 +501,12 @@ mod tests {
Ok(store)
}

fn build_basic_config_and_header(
istanbul_active: bool,
shanghai_active: bool,
) -> (ChainConfig, BlockHeader) {
fn build_basic_config_and_header(shanghai_active: bool) -> (ChainConfig, BlockHeader) {
use ethrex_common::types::FORKS;
let mut fork_activation_timestamps: [Option<u64>; FORKS.len()] = [None; FORKS.len()];
fork_activation_timestamps[Shanghai] = Some(if shanghai_active { 1 } else { 10 });
let config = ChainConfig {
shanghai_time: Some(if shanghai_active { 1 } else { 10 }),
istanbul_block: Some(if istanbul_active { 1 } else { 10 }),
fork_activation_timestamps,
..Default::default()
};

Expand All @@ -528,7 +523,7 @@ mod tests {

#[test]
fn normal_transaction_intrinsic_gas() {
let (config, header) = build_basic_config_and_header(false, false);
let (config, header) = build_basic_config_and_header(false);

let tx = EIP1559Transaction {
nonce: 3,
Expand All @@ -551,7 +546,7 @@ mod tests {

#[test]
fn create_transaction_intrinsic_gas() {
let (config, header) = build_basic_config_and_header(false, false);
let (config, header) = build_basic_config_and_header(false);

let tx = EIP1559Transaction {
nonce: 3,
Expand All @@ -573,8 +568,8 @@ mod tests {
}

#[test]
fn transaction_intrinsic_data_gas_pre_istanbul() {
let (config, header) = build_basic_config_and_header(false, false);
fn transaction_intrinsic_data_gas() {
let (config, header) = build_basic_config_and_header(false);

let tx = EIP1559Transaction {
nonce: 3,
Expand All @@ -595,33 +590,9 @@ mod tests {
assert_eq!(intrinsic_gas, expected_gas_cost);
}

#[test]
fn transaction_intrinsic_data_gas_post_istanbul() {
let (config, header) = build_basic_config_and_header(true, false);

let tx = EIP1559Transaction {
nonce: 3,
max_priority_fee_per_gas: 0,
max_fee_per_gas: 0,
gas_limit: 100_000,
to: TxKind::Call(Address::from_low_u64_be(1)), // Normal tx
value: U256::zero(), // Value zero
data: Bytes::from(vec![0x0, 0x1, 0x1, 0x0, 0x1, 0x1]), // 6 bytes of data
access_list: Default::default(), // No access list
..Default::default()
};

let tx = Transaction::EIP1559Transaction(tx);
let expected_gas_cost =
TX_GAS_COST + 2 * TX_DATA_ZERO_GAS_COST + 4 * TX_DATA_NON_ZERO_GAS_EIP2028;
let intrinsic_gas =
transaction_intrinsic_gas(&tx, &header, &config).expect("Intrinsic gas");
assert_eq!(intrinsic_gas, expected_gas_cost);
}

#[test]
fn transaction_create_intrinsic_gas_pre_shanghai() {
let (config, header) = build_basic_config_and_header(false, false);
let (config, header) = build_basic_config_and_header(false);

let n_words: u64 = 10;
let n_bytes: u64 = 32 * n_words - 3; // Test word rounding
Expand All @@ -647,7 +618,7 @@ mod tests {

#[test]
fn transaction_create_intrinsic_gas_post_shanghai() {
let (config, header) = build_basic_config_and_header(false, true);
let (config, header) = build_basic_config_and_header(true);

let n_words: u64 = 10;
let n_bytes: u64 = 32 * n_words - 3; // Test word rounding
Expand Down Expand Up @@ -675,7 +646,7 @@ mod tests {

#[test]
fn transaction_intrinsic_gas_access_list() {
let (config, header) = build_basic_config_and_header(false, false);
let (config, header) = build_basic_config_and_header(false);

let access_list = vec![
(Address::zero(), vec![H256::default(); 10]),
Expand Down Expand Up @@ -705,7 +676,7 @@ mod tests {

#[tokio::test]
async fn transaction_with_big_init_code_in_shanghai_fails() {
let (config, header) = build_basic_config_and_header(false, true);
let (config, header) = build_basic_config_and_header(true);

let store = setup_storage(config, header).await.expect("Storage setup");
let blockchain = Blockchain::default_with_store(store);
Expand All @@ -732,7 +703,7 @@ mod tests {

#[tokio::test]
async fn transaction_with_gas_limit_higher_than_of_the_block_should_fail() {
let (config, header) = build_basic_config_and_header(false, false);
let (config, header) = build_basic_config_and_header(false);

let store = setup_storage(config, header).await.expect("Storage setup");
let blockchain = Blockchain::default_with_store(store);
Expand All @@ -759,7 +730,7 @@ mod tests {

#[tokio::test]
async fn transaction_with_priority_fee_higher_than_gas_fee_should_fail() {
let (config, header) = build_basic_config_and_header(false, false);
let (config, header) = build_basic_config_and_header(false);

let store = setup_storage(config, header).await.expect("Storage setup");
let blockchain = Blockchain::default_with_store(store);
Expand All @@ -786,7 +757,7 @@ mod tests {

#[tokio::test]
async fn transaction_with_gas_limit_lower_than_intrinsic_gas_should_fail() {
let (config, header) = build_basic_config_and_header(false, false);
let (config, header) = build_basic_config_and_header(false);
let store = setup_storage(config, header).await.expect("Storage setup");
let blockchain = Blockchain::default_with_store(store);
let intrinsic_gas_cost = TX_GAS_COST;
Expand All @@ -813,7 +784,7 @@ mod tests {

#[tokio::test]
async fn transaction_with_blob_base_fee_below_min_should_fail() {
let (config, header) = build_basic_config_and_header(false, false);
let (config, header) = build_basic_config_and_header(false);
let store = setup_storage(config, header).await.expect("Storage setup");
let blockchain = Blockchain::default_with_store(store);

Expand Down
26 changes: 9 additions & 17 deletions crates/blockchain/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use ethrex_common::{
constants::{DEFAULT_OMMERS_HASH, DEFAULT_REQUESTS_HASH, GAS_PER_BLOB, MAX_RLP_BLOCK_SIZE},
types::{
AccountUpdate, BlobsBundle, Block, BlockBody, BlockHash, BlockHeader, BlockNumber,
ChainConfig, MempoolTransaction, Receipt, Transaction, TxType, Withdrawal, bloom_from_logs,
ChainConfig,
Fork::*,
MempoolTransaction, Receipt, Transaction, TxType, Withdrawal, bloom_from_logs,
calc_excess_blob_gas, calculate_base_fee_per_blob_gas, calculate_base_fee_per_gas,
compute_receipts_root, compute_transactions_root, compute_withdrawals_root,
requests::{EncodedRequests, compute_requests_hash},
Expand Down Expand Up @@ -159,17 +161,17 @@ pub fn create_payload(
args.elasticity_multiplier,
),
withdrawals_root: chain_config
.is_shanghai_activated(args.timestamp)
.is_fork_activated(Shanghai, args.timestamp)
.then_some(compute_withdrawals_root(
args.withdrawals.as_ref().unwrap_or(&Vec::new()),
)),
blob_gas_used: chain_config
.is_cancun_activated(args.timestamp)
.is_fork_activated(Cancun, args.timestamp)
.then_some(0),
excess_blob_gas,
parent_beacon_block_root: args.beacon_root,
requests_hash: chain_config
.is_prague_activated(args.timestamp)
.is_fork_activated(Prague, args.timestamp)
.then_some(*DEFAULT_REQUESTS_HASH),
..Default::default()
};
Expand Down Expand Up @@ -247,7 +249,7 @@ impl PayloadBuildContext {
remaining_gas: payload.header.gas_limit,
receipts: vec![],
requests: config
.is_prague_activated(payload.header.timestamp)
.is_fork_activated(Prague, payload.header.timestamp)
.then_some(Vec::new()),
block_value: U256::zero(),
base_fee_per_blob_gas,
Expand Down Expand Up @@ -543,7 +545,7 @@ impl Blockchain {
context.payload_size + head_tx.encode_canonical_to_vec().len() as u64;
if context
.chain_config()
.is_osaka_activated(context.payload.header.timestamp)
.is_fork_activated(Osaka, context.payload.header.timestamp)
&& potential_rlp_block_size > MAX_RLP_BLOCK_SIZE
{
break;
Expand All @@ -553,16 +555,6 @@ impl Blockchain {
// TODO: maybe fetch hash too when filtering mempool so we don't have to compute it here (we can do this in the same refactor as adding timestamp)
let tx_hash = head_tx.tx.hash();

// Check whether the tx is replay-protected
if head_tx.tx.protected() && !chain_config.is_eip155_activated(context.block_number()) {
// Ignore replay protected tx & all txs from the sender
// Pull transaction from the mempool
debug!("Ignoring replay-protected transaction: {}", tx_hash);
txs.pop();
self.remove_transaction_from_pool(&tx_hash)?;
continue;
}

// Execute tx
let receipt = match self.apply_transaction(&head_tx, context) {
Ok(receipt) => {
Expand Down Expand Up @@ -636,7 +628,7 @@ impl Blockchain {
pub fn extract_requests(&self, context: &mut PayloadBuildContext) -> Result<(), EvmError> {
if !context
.chain_config()
.is_prague_activated(context.payload.header.timestamp)
.is_fork_activated(Prague, context.payload.header.timestamp)
{
return Ok(());
};
Expand Down
Loading
Loading