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 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
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
5 changes: 5 additions & 0 deletions core/src/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ fn eval_jumpdest(_state: &mut Machine, _opcode: Opcode, _position: usize) -> Con
Control::Continue(1)
}

fn eval_push0(state: &mut Machine, _opcode: Opcode, position: usize) -> Control {
self::misc::push(state, 0, position)
}

fn eval_push1(state: &mut Machine, _opcode: Opcode, position: usize) -> Control {
self::misc::push(state, 1, position)
}
Expand Down Expand Up @@ -494,6 +498,7 @@ pub fn eval(state: &mut Machine, opcode: Opcode, position: usize) -> Control {
table[Opcode::MSIZE.as_usize()] = eval_msize as _;
table[Opcode::JUMPDEST.as_usize()] = eval_jumpdest as _;

table[Opcode::PUSH0.as_usize()] = eval_push0 as _;
table[Opcode::PUSH1.as_usize()] = eval_push1 as _;
table[Opcode::PUSH2.as_usize()] = eval_push2 as _;
table[Opcode::PUSH3.as_usize()] = eval_push3 as _;
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
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),
}
}
}
57 changes: 55 additions & 2 deletions src/executor/stack/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,23 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet>
gasometer.record_transaction(transaction_cost)
}

fn maybe_record_init_code_cost(&mut self, init_code: &[u8]) -> Result<(), ExitError> {
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);
return Err(ExitError::OutOfGas);
}
return self
.state
.metadata_mut()
.gasometer
.record_cost(gasometer::init_code_cost(init_code));
}
Ok(())
}

/// Execute a `CREATE` transaction.
pub fn transact_create(
&mut self,
Expand All @@ -458,6 +475,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 +511,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 +587,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 @@ -1104,6 +1145,12 @@ 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 Err(e) = self.maybe_record_init_code_cost(&init_code) {
let reason: ExitReason = e.into();
emit_exit!(reason.clone());
return Capture::Exit((reason, None, Vec::new()));
}

self.create_inner(caller, scheme, value, init_code, target_gas, true)
}

Expand All @@ -1116,6 +1163,12 @@ 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 Err(e) = self.maybe_record_init_code_cost(&init_code) {
let reason: ExitReason = e.into();
emit_exit!(reason.clone());
return Capture::Exit((reason, 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