Skip to content

Commit

Permalink
feat: replace DIFFICULTY with PREVRANDAO since merge (EIP-4399)
Browse files Browse the repository at this point in the history
  • Loading branch information
vimpunk committed Apr 27, 2023
1 parent 75ade29 commit a3712ca
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 9 deletions.
1 change: 1 addition & 0 deletions benches/loop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ fn run_loop_contract() {
block_gas_limit: Default::default(),
chain_id: U256::one(),
block_base_fee_per_gas: U256::zero(),
block_randomness: None,
};

let mut state = BTreeMap::new();
Expand Down
10 changes: 7 additions & 3 deletions core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,6 @@ pub enum ExitError {
/// Create init code exceeds limit (runtime).
#[cfg_attr(feature = "with-codec", codec(index = 7))]
CreateContractLimit,
/// Invalid opcode during execution or starting byte is 0xef. See [EIP-3541](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3541.md).
#[cfg_attr(feature = "with-codec", codec(index = 15))]
InvalidCode(Opcode),

/// An opcode accesses external information, but the request is off offset
/// limit (runtime).
Expand All @@ -154,6 +151,13 @@ pub enum ExitError {
/// Other normal errors.
#[cfg_attr(feature = "with-codec", codec(index = 13))]
Other(Cow<'static, str>),

/// Randomness was not configured for the PREVRANDAO opcode
#[cfg_attr(feature = "with-codec", codec(index = 14))]
MissingRandomness,
/// Invalid opcode during execution or starting byte is 0xef. See [EIP-3541](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3541.md).
#[cfg_attr(feature = "with-codec", codec(index = 15))]
InvalidCode(Opcode),
}

impl From<ExitError> for ExitReason {
Expand Down
15 changes: 13 additions & 2 deletions runtime/src/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ pub enum Control<H: Handler> {
Exit(ExitReason),
}

fn handle_other<H: Handler>(state: &mut Runtime<'_>, opcode: Opcode, handler: &mut H) -> Control<H> {
fn handle_other<H: Handler>(
state: &mut Runtime<'_>,
opcode: Opcode,
handler: &mut H,
) -> Control<H> {
match handler.other(opcode, &mut state.machine) {
Ok(()) => Control::Continue,
Err(e) => Control::Exit(e.into()),
Expand All @@ -40,7 +44,14 @@ pub fn eval<H: Handler>(state: &mut Runtime<'_>, opcode: Opcode, handler: &mut H
Opcode::COINBASE => system::coinbase(state, handler),
Opcode::TIMESTAMP => system::timestamp(state, handler),
Opcode::NUMBER => system::number(state, handler),
Opcode::DIFFICULTY => system::difficulty(state, handler),
Opcode::DIFFICULTY => {
// system::difficulty(state, handler)
if state.config().has_prevrandao {
system::prevrandao(state, handler)
} else {
system::difficulty(state, handler)
}
}
Opcode::GASLIMIT => system::gaslimit(state, handler),
Opcode::SLOAD => system::sload(state, handler),
Opcode::SSTORE => system::sstore(state, handler),
Expand Down
31 changes: 29 additions & 2 deletions runtime/src/eval/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,25 @@ pub fn difficulty<H: Handler>(runtime: &mut Runtime<'_>, handler: &H) -> Control
Control::Continue
}

pub fn prevrandao<H: Handler>(runtime: &mut Runtime, handler: &H) -> Control<H> {
match handler.block_randomness() {
Some(rand) => {
// Convert between U256 and H256. U256 is in little-endian but since H256 is just
// a string-like byte array, it's big endian (MSB is the first element of the hash).
//
// Byte order here is important because this opcode has the same value as DIFFICULTY
// (0x44), and so for older forks of Ethereum, the threshold value of 2^64 is used to
// distinguish between the two: if it's below, the value corresponds to the DIFFICULTY
// opcode, otherwise to the PREVRANDAO opcode.
let mut buf = [0u8; 32];
rand.to_big_endian(&mut buf);
push!(runtime, H256(buf));
Control::Continue
}
None => Control::Exit(ExitError::MissingRandomness.into()),
}
}

pub fn gaslimit<H: Handler>(runtime: &mut Runtime<'_>, handler: &H) -> Control<H> {
push_u256!(runtime, handler.block_gas_limit());
Control::Continue
Expand Down Expand Up @@ -265,7 +284,11 @@ pub fn suicide<H: Handler>(runtime: &mut Runtime<'_>, handler: &mut H) -> Contro
Control::Exit(ExitSucceed::Suicided.into())
}

pub fn create<H: Handler>(runtime: &mut Runtime<'_>, is_create2: bool, handler: &mut H) -> Control<H> {
pub fn create<H: Handler>(
runtime: &mut Runtime<'_>,
is_create2: bool,
handler: &mut H,
) -> Control<H> {
runtime.return_data_buffer = Vec::new();

pop_u256!(runtime, value, code_offset, len);
Expand Down Expand Up @@ -305,7 +328,11 @@ pub fn create<H: Handler>(runtime: &mut Runtime<'_>, is_create2: bool, handler:
}
}

pub fn call<H: Handler>(runtime: &mut Runtime<'_>, scheme: CallScheme, handler: &mut H) -> Control<H> {
pub fn call<H: Handler>(
runtime: &mut Runtime<'_>,
scheme: CallScheme,
handler: &mut H,
) -> Control<H> {
runtime.return_data_buffer = Vec::new();

pop_u256!(runtime, gas);
Expand Down
2 changes: 2 additions & 0 deletions runtime/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ pub trait Handler {
fn block_timestamp(&self) -> U256;
/// Get environmental block difficulty.
fn block_difficulty(&self) -> U256;
/// Get environmental block randomness.
fn block_randomness(&self) -> Option<U256>;
/// Get environmental gas limit.
fn block_gas_limit(&self) -> U256;
/// Environmental block base fee.
Expand Down
40 changes: 38 additions & 2 deletions runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ pub struct Runtime<'config> {
return_data_len: U256,
return_data_offset: U256,
context: Context,
_config: &'config Config,
config: &'config Config,
}

impl<'config> Runtime<'config> {
Expand All @@ -132,7 +132,7 @@ impl<'config> Runtime<'config> {
return_data_len: U256::zero(),
return_data_offset: U256::zero(),
context,
_config: config,
config,
}
}

Expand All @@ -146,6 +146,11 @@ impl<'config> Runtime<'config> {
&self.context
}

/// Get a reference to the runtime config.
pub fn config(&self) -> &'config Config {
self.config
}

/// Step the runtime.
pub fn step<'a, H: Handler>(
&'a mut self,
Expand Down Expand Up @@ -287,6 +292,9 @@ pub struct Config {
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,
/// Has PREVRANDAO opcode, replacing the DIFFICULTY opcode.
/// See [EIP-4399](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4399.md)
pub has_prevrandao: bool,
/// Whether the gasometer is running in estimate mode.
pub estimate: bool,
}
Expand Down Expand Up @@ -342,6 +350,7 @@ impl Config {
has_ext_code_hash: false,
has_base_fee: false,
has_push0: false,
has_prevrandao: false,
estimate: false,
}
}
Expand Down Expand Up @@ -396,6 +405,7 @@ impl Config {
has_ext_code_hash: true,
has_base_fee: false,
has_push0: false,
has_prevrandao: false,
estimate: false,
}
}
Expand All @@ -410,6 +420,11 @@ impl Config {
Self::config_with_derived_values(DerivedConfigInputs::london())
}

/// The Merge (Paris) hard fork configuration.
pub const fn merge() -> Config {
Self::config_with_derived_values(DerivedConfigInputs::merge())
}

/// Shanghai hard fork configuration.
pub const fn shanghai() -> Config {
Self::config_with_derived_values(DerivedConfigInputs::shanghai())
Expand All @@ -423,6 +438,7 @@ impl Config {
decrease_clears_refund,
has_base_fee,
has_push0,
has_prevrandao,
disallow_executable_format,
warm_coinbase_address,
max_initcode_size,
Expand Down Expand Up @@ -488,6 +504,7 @@ impl Config {
has_ext_code_hash: true,
has_base_fee,
has_push0,
has_prevrandao,
estimate: false,
}
}
Expand All @@ -502,6 +519,7 @@ struct DerivedConfigInputs {
decrease_clears_refund: bool,
has_base_fee: bool,
has_push0: bool,
has_prevrandao: bool,
disallow_executable_format: bool,
warm_coinbase_address: bool,
max_initcode_size: Option<usize>,
Expand All @@ -516,6 +534,7 @@ impl DerivedConfigInputs {
decrease_clears_refund: false,
has_base_fee: false,
has_push0: false,
has_prevrandao: false,
disallow_executable_format: false,
warm_coinbase_address: false,
max_initcode_size: None,
Expand All @@ -530,6 +549,22 @@ impl DerivedConfigInputs {
decrease_clears_refund: true,
has_base_fee: true,
has_push0: false,
has_prevrandao: false,
disallow_executable_format: true,
warm_coinbase_address: false,
max_initcode_size: None,
}
}

const fn merge() -> 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: false,
has_prevrandao: true,
disallow_executable_format: true,
warm_coinbase_address: false,
max_initcode_size: None,
Expand All @@ -544,6 +579,7 @@ impl DerivedConfigInputs {
decrease_clears_refund: true,
has_base_fee: true,
has_push0: true,
has_prevrandao: true,
disallow_executable_format: true,
warm_coinbase_address: true,
// 2 * 24576 as per EIP-3860
Expand Down
8 changes: 8 additions & 0 deletions src/backend/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ pub struct MemoryVicinity {
pub block_gas_limit: U256,
/// Environmental base fee per gas.
pub block_base_fee_per_gas: U256,
/// Environmental randomness.
///
/// In Ethereum, this is the randomness beacon provided by the beacon
/// chain and is only enabled post Merge.
pub block_randomness: Option<U256>,
}

/// Account information of a memory backend.
Expand Down Expand Up @@ -110,6 +115,9 @@ impl<'vicinity> Backend for MemoryBackend<'vicinity> {
fn block_difficulty(&self) -> U256 {
self.vicinity.block_difficulty
}
fn block_randomness(&self) -> Option<U256> {
self.vicinity.block_randomness
}
fn block_gas_limit(&self) -> U256 {
self.vicinity.block_gas_limit
}
Expand Down
2 changes: 2 additions & 0 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ pub trait Backend {
fn block_timestamp(&self) -> U256;
/// Environmental block difficulty.
fn block_difficulty(&self) -> U256;
/// Get environmental block randomness.
fn block_randomness(&self) -> Option<U256>;
/// Environmental block gas limit.
fn block_gas_limit(&self) -> U256;
/// Environmental block base fee.
Expand Down
3 changes: 3 additions & 0 deletions src/executor/stack/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1101,6 +1101,9 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler
fn block_difficulty(&self) -> U256 {
self.state.block_difficulty()
}
fn block_randomness(&self) -> Option<U256> {
self.state.block_randomness()
}
fn block_gas_limit(&self) -> U256 {
self.state.block_gas_limit()
}
Expand Down
3 changes: 3 additions & 0 deletions src/executor/stack/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,9 @@ impl<'backend, 'config, B: Backend> Backend for MemoryStackState<'backend, 'conf
fn block_difficulty(&self) -> U256 {
self.backend.block_difficulty()
}
fn block_randomness(&self) -> Option<U256> {
self.backend.block_randomness()
}
fn block_gas_limit(&self) -> U256 {
self.backend.block_gas_limit()
}
Expand Down

0 comments on commit a3712ca

Please sign in to comment.