Skip to content
Open
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
25 changes: 13 additions & 12 deletions crates/blockchain/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ 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};
Expand Down Expand Up @@ -1255,7 +1255,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 @@ -1266,7 +1266,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 @@ -1400,7 +1401,7 @@ impl Blockchain {
.storage
.get_block_header(latest_block_number)?
.ok_or(StoreError::Custom("Latest block not in DB".to_string()))?;
Ok(chain_config.fork(latest_block.timestamp))
Ok(chain_config.get_fork(latest_block.timestamp))
}
}

Expand All @@ -1423,7 +1424,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 @@ -1510,7 +1511,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 @@ -1521,14 +1522,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 Expand Up @@ -1570,7 +1571,7 @@ fn verify_blob_gas_usage(block: &Block, config: &ChainConfig) -> Result<(), Chai
let mut blob_gas_used = 0_u32;
let mut blobs_in_block = 0_u32;
let max_blob_number_per_block = config
.get_fork_blob_schedule(block.header.timestamp)
.get_blob_schedule_for_time(block.header.timestamp)
.map(|schedule| schedule.max)
.ok_or(ChainError::Custom("Provided block fork is invalid".into()))?;
let max_blob_gas_per_block = max_blob_number_per_block * GAS_PER_BLOB;
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
46 changes: 8 additions & 38 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,16 +427,10 @@ 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_count = tx.data().iter().filter(|&&x| x != 0u8).count() as u64;

gas = gas
.checked_add(non_zero_count * non_zero_gas_cost)
.checked_add(non_zero_count * TX_DATA_NON_ZERO_GAS)
.ok_or(MempoolError::TxGasOverflowError)?;

let zero_count = data_len - non_zero_count;
Expand All @@ -444,7 +439,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 +472,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 Down Expand Up @@ -572,29 +566,6 @@ mod tests {
assert_eq!(intrinsic_gas, expected_gas_cost);
}

#[test]
fn transaction_intrinsic_data_gas_pre_istanbul() {
let (config, header) = build_basic_config_and_header(false, 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;
let intrinsic_gas =
transaction_intrinsic_gas(&tx, &header, &config).expect("Intrinsic gas");
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);
Expand All @@ -612,8 +583,7 @@ mod tests {
};

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 expected_gas_cost = TX_GAS_COST + 2 * TX_DATA_ZERO_GAS_COST + 4 * TX_DATA_NON_ZERO_GAS;
let intrinsic_gas =
transaction_intrinsic_gas(&tx, &header, &config).expect("Intrinsic gas");
assert_eq!(intrinsic_gas, expected_gas_cost);
Expand Down
36 changes: 14 additions & 22 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 @@ -128,10 +130,10 @@ pub fn create_payload(
.get_block_header_by_hash(args.parent)?
.ok_or_else(|| ChainError::ParentNotFound)?;
let chain_config = storage.get_chain_config();
let fork = chain_config.fork(args.timestamp);
let fork = chain_config.get_fork(args.timestamp);
let gas_limit = calc_gas_limit(parent_block.gas_limit, args.gas_ceil);
let excess_blob_gas = chain_config
.get_fork_blob_schedule(args.timestamp)
.get_blob_schedule_for_time(args.timestamp)
.map(|schedule| calc_excess_blob_gas(&parent_block, schedule, fork));

let header = BlockHeader {
Expand All @@ -158,17 +160,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 @@ -229,7 +231,7 @@ impl PayloadBuildContext {
let base_fee_per_blob_gas = calculate_base_fee_per_blob_gas(
payload.header.excess_blob_gas.unwrap_or_default(),
config
.get_fork_blob_schedule(payload.header.timestamp)
.get_blob_schedule_for_time(payload.header.timestamp)
.map(|schedule| schedule.base_fee_update_fraction)
.unwrap_or_default(),
);
Expand All @@ -246,7 +248,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 @@ -493,7 +495,7 @@ impl Blockchain {
pub fn fill_transactions(&self, context: &mut PayloadBuildContext) -> Result<(), ChainError> {
let chain_config = context.chain_config();
let max_blob_number_per_block = chain_config
.get_fork_blob_schedule(context.payload.header.timestamp)
.get_blob_schedule_for_time(context.payload.header.timestamp)
.map(|schedule| schedule.max)
.unwrap_or_default() as usize;

Expand Down Expand Up @@ -542,7 +544,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 @@ -552,16 +554,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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

state tests don't use this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They aren't failing on the CI and they aren't failing locally either, so preseumably not.

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 @@ -609,7 +601,7 @@ impl Blockchain {
let tx_hash = head.tx.hash();
let chain_config = context.chain_config();
let max_blob_number_per_block = chain_config
.get_fork_blob_schedule(context.payload.header.timestamp)
.get_blob_schedule_for_time(context.payload.header.timestamp)
.map(|schedule| schedule.max)
.unwrap_or_default() as usize;
let Some(blobs_bundle) = self.mempool.get_blobs_bundle(tx_hash)? else {
Expand All @@ -635,7 +627,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
8 changes: 6 additions & 2 deletions crates/common/types/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -732,9 +732,13 @@ fn validate_excess_blob_gas(
chain_config: &ChainConfig,
) -> Result<(), InvalidBlockHeaderError> {
let expected_excess_blob_gas = chain_config
.get_fork_blob_schedule(header.timestamp)
.get_blob_schedule_for_time(header.timestamp)
.map(|schedule| {
calc_excess_blob_gas(parent_header, schedule, chain_config.fork(header.timestamp))
calc_excess_blob_gas(
parent_header,
schedule,
chain_config.get_fork(header.timestamp),
)
})
.unwrap_or_default();
if header
Expand Down
Loading
Loading