Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

shanghai eips 3651, 3855, 3860 #152

Merged
merged 7 commits into from
Mar 8, 2023
Merged
Show file tree
Hide file tree
Changes from 5 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
4 changes: 4 additions & 0 deletions core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ pub enum ExitError {
/// Other normal errors.
#[cfg_attr(feature = "with-codec", codec(index = 13))]
Other(Cow<'static, str>),

/// Init code exceeds limit (runtime).
#[cfg_attr(feature = "with-codec", codec(index = 7))]
InitCodeLimit,
}

impl From<ExitError> for ExitReason {
Expand Down
1 change: 1 addition & 0 deletions core/src/opcode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ impl Opcode {
pub const JUMPDEST: Opcode = Opcode(0x5b);

/// `PUSHn`
pub const PUSH0: Opcode = Opcode(0x5f);
pub const PUSH1: Opcode = Opcode(0x60);
pub const PUSH2: Opcode = Opcode(0x61);
pub const PUSH3: Opcode = Opcode(0x62);
Expand Down
19 changes: 17 additions & 2 deletions gasometer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,12 +238,17 @@ impl<'config> Gasometer<'config> {
non_zero_data_len,
access_list_address_len,
access_list_storage_len,
initcode_cost,
} => {
self.config.gas_transaction_create
let mut cost = self.config.gas_transaction_create
+ zero_data_len as u64 * self.config.gas_transaction_zero_data
+ non_zero_data_len as u64 * self.config.gas_transaction_non_zero_data
+ access_list_address_len as u64 * self.config.gas_access_list_address
+ access_list_storage_len as u64 * self.config.gas_access_list_storage_key
+ access_list_storage_len as u64 * self.config.gas_access_list_storage_key;
if self.config.max_initcode_size.is_some() {
cost += initcode_cost;
}
cost
}
};

Expand Down Expand Up @@ -293,15 +298,21 @@ pub fn create_transaction_cost(data: &[u8], access_list: &[(H160, Vec<H256>)]) -
let zero_data_len = data.iter().filter(|v| **v == 0).count();
let non_zero_data_len = data.len() - zero_data_len;
let (access_list_address_len, access_list_storage_len) = count_access_list(access_list);
let initcode_cost = init_code_cost(data);

TransactionCost::Create {
zero_data_len,
non_zero_data_len,
access_list_address_len,
access_list_storage_len,
initcode_cost,
}
}

pub fn init_code_cost(data: &[u8]) -> u64 {
2 * (data.len() as u64 / 32)
}

/// Counts the number of addresses and storage keys in the access list
fn count_access_list(access_list: &[(H160, Vec<H256>)]) -> (usize, usize) {
let access_list_address_len = access_list.len();
Expand Down Expand Up @@ -610,6 +621,8 @@ pub fn dynamic_opcode_cost<H: Handler>(
}
}

Opcode::PUSH0 if config.has_push0 => GasCost::Base,

_ => GasCost::Invalid(opcode),
};

Expand Down Expand Up @@ -1021,6 +1034,8 @@ pub enum TransactionCost {
access_list_address_len: usize,
/// Total number of storage keys in transaction access list (see EIP-2930)
access_list_storage_len: usize,
/// Cost of initcode = 2 * ceil(len(initcode) / 32) (see EIP-3860)
initcode_cost: u64,
},
}

Expand Down
1 change: 1 addition & 0 deletions runtime/src/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub fn eval<H: Handler>(state: &mut Runtime, opcode: Opcode, handler: &mut H) ->
Opcode::STATICCALL => system::call(state, CallScheme::StaticCall, handler),
Opcode::CHAINID => system::chainid(state, handler),
Opcode::BASEFEE => system::base_fee(state, handler),
Opcode::PUSH0 => system::push0(state),
_ => handle_other(state, opcode, handler),
}
}
6 changes: 6 additions & 0 deletions runtime/src/eval/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ pub fn base_fee<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
Control::Continue
}

pub fn push0<H: Handler>(runtime: &mut Runtime) -> Control<H> {
tgmichel marked this conversation as resolved.
Show resolved Hide resolved
push!(runtime, H256::default());

Control::Continue
}

pub fn extcodesize<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
pop!(runtime, address);
push_u256!(runtime, handler.code_size(address.into()));
Expand Down
46 changes: 46 additions & 0 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,8 @@ pub struct Config {
pub decrease_clears_refund: bool,
/// EIP-3541
pub disallow_executable_format: bool,
/// EIP-3651
pub warm_coinbase_address: bool,
/// Whether to throw out of gas error when
/// CALL/CALLCODE/DELEGATECALL requires more than maximum amount
/// of gas.
Expand All @@ -233,6 +235,8 @@ pub struct Config {
pub call_stack_limit: usize,
/// Create contract limit.
pub create_contract_limit: Option<usize>,
/// EIP-3860, maximum size limit of init_code.
pub max_initcode_size: Option<usize>,
/// Call stipend.
pub call_stipend: u64,
/// Has delegate call.
Expand All @@ -253,6 +257,8 @@ pub struct Config {
pub has_ext_code_hash: bool,
/// Has ext block fee. See [EIP-3198](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3198.md)
pub has_base_fee: bool,
/// Has PUSH0 opcode. See [EIP-3855](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3855.md)
pub has_push0: bool,
/// Whether the gasometer is running in estimate mode.
pub estimate: bool,
}
Expand Down Expand Up @@ -287,6 +293,7 @@ impl Config {
increase_state_access_gas: false,
decrease_clears_refund: false,
disallow_executable_format: false,
warm_coinbase_address: false,
err_on_call_with_more_gas: true,
empty_considered_exists: true,
create_increase_nonce: false,
Expand All @@ -295,6 +302,7 @@ impl Config {
memory_limit: usize::MAX,
call_stack_limit: 1024,
create_contract_limit: None,
max_initcode_size: None,
call_stipend: 2300,
has_delegate_call: false,
has_create2: false,
Expand All @@ -305,6 +313,7 @@ impl Config {
has_self_balance: false,
has_ext_code_hash: false,
has_base_fee: false,
has_push0: false,
estimate: false,
}
}
Expand Down Expand Up @@ -338,6 +347,7 @@ impl Config {
increase_state_access_gas: false,
decrease_clears_refund: false,
disallow_executable_format: false,
warm_coinbase_address: false,
err_on_call_with_more_gas: false,
empty_considered_exists: false,
create_increase_nonce: true,
Expand All @@ -346,6 +356,7 @@ impl Config {
memory_limit: usize::MAX,
call_stack_limit: 1024,
create_contract_limit: Some(0x6000),
max_initcode_size: None,
call_stipend: 2300,
has_delegate_call: true,
has_create2: true,
Expand All @@ -356,6 +367,7 @@ impl Config {
has_self_balance: true,
has_ext_code_hash: true,
has_base_fee: false,
has_push0: false,
estimate: false,
}
}
Expand All @@ -370,14 +382,22 @@ impl Config {
Self::config_with_derived_values(DerivedConfigInputs::london())
}

/// Shanghai hard fork configuration.
pub const fn shanghai() -> Config {
Self::config_with_derived_values(DerivedConfigInputs::shanghai())
}

const fn config_with_derived_values(inputs: DerivedConfigInputs) -> Config {
let DerivedConfigInputs {
gas_storage_read_warm,
gas_sload_cold,
gas_access_list_storage_key,
decrease_clears_refund,
has_base_fee,
has_push0,
disallow_executable_format,
warm_coinbase_address,
max_initcode_size,
} = inputs;

// See https://eips.ethereum.org/EIPS/eip-2929
Expand Down Expand Up @@ -419,6 +439,7 @@ impl Config {
increase_state_access_gas: true,
decrease_clears_refund,
disallow_executable_format,
warm_coinbase_address,
err_on_call_with_more_gas: false,
empty_considered_exists: false,
create_increase_nonce: true,
Expand All @@ -427,6 +448,7 @@ impl Config {
memory_limit: usize::MAX,
call_stack_limit: 1024,
create_contract_limit: Some(0x6000),
max_initcode_size,
call_stipend: 2300,
has_delegate_call: true,
has_create2: true,
Expand All @@ -437,6 +459,7 @@ impl Config {
has_self_balance: true,
has_ext_code_hash: true,
has_base_fee,
has_push0,
estimate: false,
}
}
Expand All @@ -450,7 +473,10 @@ struct DerivedConfigInputs {
gas_access_list_storage_key: u64,
decrease_clears_refund: bool,
has_base_fee: bool,
has_push0: bool,
disallow_executable_format: bool,
warm_coinbase_address: bool,
max_initcode_size: Option<usize>,
}

impl DerivedConfigInputs {
Expand All @@ -461,7 +487,10 @@ impl DerivedConfigInputs {
gas_access_list_storage_key: 1900,
decrease_clears_refund: false,
has_base_fee: false,
has_push0: false,
disallow_executable_format: false,
warm_coinbase_address: false,
max_initcode_size: None,
}
}

Expand All @@ -472,7 +501,24 @@ impl DerivedConfigInputs {
gas_access_list_storage_key: 1900,
decrease_clears_refund: true,
has_base_fee: true,
has_push0: false,
disallow_executable_format: true,
warm_coinbase_address: false,
max_initcode_size: None,
}
}

const fn shanghai() -> Self {
Self {
gas_storage_read_warm: 100,
gas_sload_cold: 2100,
gas_access_list_storage_key: 1900,
decrease_clears_refund: true,
has_base_fee: true,
has_push0: true,
disallow_executable_format: true,
warm_coinbase_address: true,
max_initcode_size: Some(0xC000),
}
}
}
46 changes: 44 additions & 2 deletions src/executor/stack/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,14 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet>
address: self.create_address(CreateScheme::Legacy { caller }),
});

if let Some(limit) = self.config.max_initcode_size {
if init_code.len() > limit {
self.state.metadata_mut().gasometer.fail();
let _ = self.exit_substate(StackExitKind::Failed);
return emit_exit!(ExitError::InitCodeLimit.into(), Vec::new());
}
}

if let Err(e) = self.record_create_transaction_cost(&init_code, &access_list) {
return emit_exit!(e.into(), Vec::new());
}
Expand Down Expand Up @@ -486,6 +494,14 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet>
gas_limit: u64,
access_list: Vec<(H160, Vec<H256>)>, // See EIP-2930
) -> (ExitReason, Vec<u8>) {
if let Some(limit) = self.config.max_initcode_size {
if init_code.len() > limit {
self.state.metadata_mut().gasometer.fail();
let _ = self.exit_substate(StackExitKind::Failed);
return emit_exit!(ExitError::InitCodeLimit.into(), Vec::new());
}
}

let code_hash = H256::from_slice(Keccak256::digest(&init_code).as_slice());
event!(TransactCreate2 {
caller,
Expand Down Expand Up @@ -554,8 +570,16 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet>

// Initialize initial addresses for EIP-2929
if self.config.increase_state_access_gas {
let addresses = core::iter::once(caller).chain(core::iter::once(address));
self.state.metadata_mut().access_addresses(addresses);
if self.config.warm_coinbase_address {
// Warm coinbase address for EIP-3651
let addresses = core::iter::once(caller)
.chain(core::iter::once(address))
.chain(core::iter::once(self.block_coinbase()));
self.state.metadata_mut().access_addresses(addresses);
} else {
let addresses = core::iter::once(caller).chain(core::iter::once(address));
self.state.metadata_mut().access_addresses(addresses);
}

self.initialize_with_access_list(access_list);
}
Expand Down Expand Up @@ -1116,6 +1140,24 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler
init_code: Vec<u8>,
target_gas: Option<u64>,
) -> Capture<(ExitReason, Option<H160>, Vec<u8>), Self::CreateInterrupt> {
if let Some(limit) = self.config.max_initcode_size {
// EIP-3860
if init_code.len() > limit {
self.state.metadata_mut().gasometer.fail();
let _ = self.exit_substate(StackExitKind::Failed);
emit_exit!(ExitError::OutOfGas.into(), Vec::new());
return Capture::Exit((ExitError::OutOfGas.into(), None, Vec::new()));
}
if let Err(e) = self
.state
.metadata_mut()
.gasometer
.record_cost(gasometer::init_code_cost(&init_code))
{
return Capture::Exit((e.into(), None, Vec::new()));
}
}

let capture = self.create_inner(caller, scheme, value, init_code, target_gas, true);

if let Capture::Exit((ref reason, _, ref return_value)) = capture {
Expand Down