Skip to content

Commit a656db9

Browse files
authored
Add support for EIP-7939 (CLZ opcode) (#400)
* feat: ✨ add support for count leading zeros (CLZ) opcode * style: 🎨 fmt * refactor: ♻️ remove redundant check * refactor: 🚨 clippy * refactor: 🚨 more clippy
1 parent 6917b13 commit a656db9

File tree

8 files changed

+647
-6
lines changed

8 files changed

+647
-6
lines changed

core/src/eval/bitwise.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,10 @@ pub fn sar(shift: U256, value: U256) -> U256 {
102102
}
103103
}
104104
}
105+
106+
/// Count leading zeros in a 256-bit value.
107+
/// Returns 256 if the value is zero.
108+
#[inline]
109+
pub fn clz(value: U256) -> U256 {
110+
U256::from(value.leading_zeros())
111+
}

core/src/eval/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ fn eval_sar(state: &mut Machine, _opcode: Opcode, _position: usize) -> Control {
120120
op2_u256_fn!(state, self::bitwise::sar)
121121
}
122122

123+
fn eval_clz(state: &mut Machine, _opcode: Opcode, _position: usize) -> Control {
124+
op1_u256_fn!(state, self::bitwise::clz)
125+
}
126+
123127
fn eval_codesize(state: &mut Machine, _opcode: Opcode, _position: usize) -> Control {
124128
self::misc::codesize(state)
125129
}
@@ -487,6 +491,7 @@ pub fn eval(state: &mut Machine, opcode: Opcode, position: usize) -> Control {
487491
table[Opcode::SHL.as_usize()] = eval_shl as _;
488492
table[Opcode::SHR.as_usize()] = eval_shr as _;
489493
table[Opcode::SAR.as_usize()] = eval_sar as _;
494+
table[Opcode::CLZ.as_usize()] = eval_clz as _;
490495
table[Opcode::CODESIZE.as_usize()] = eval_codesize as _;
491496
table[Opcode::CODECOPY.as_usize()] = eval_codecopy as _;
492497
table[Opcode::CALLDATALOAD.as_usize()] = eval_calldataload as _;

core/src/opcode.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ impl Opcode {
7979
pub const SHR: Opcode = Opcode(0x1c);
8080
/// `SAR`
8181
pub const SAR: Opcode = Opcode(0x1d);
82+
/// `CLZ` - Count leading zeros (EIP-7939)
83+
pub const CLZ: Opcode = Opcode(0x1e);
8284

8385
/// `POP`
8486
pub const POP: Opcode = Opcode(0x50);

gasometer/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,9 @@ pub fn dynamic_opcode_cost<H: Handler>(
592592
Opcode::SHL | Opcode::SHR | Opcode::SAR if config.has_bitwise_shifting => GasCost::VeryLow,
593593
Opcode::SHL | Opcode::SHR | Opcode::SAR => GasCost::Invalid(opcode),
594594

595+
Opcode::CLZ if config.has_eip_7939 => GasCost::Low,
596+
Opcode::CLZ => GasCost::Invalid(opcode),
597+
595598
Opcode::SELFBALANCE if config.has_self_balance => GasCost::Low,
596599
Opcode::SELFBALANCE => GasCost::Invalid(opcode),
597600

runtime/src/eval/system.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub fn sha3<H: Handler>(runtime: &mut Runtime) -> Control<H> {
2121
};
2222

2323
let ret = Keccak256::digest(data.as_slice());
24-
push!(runtime, H256::from_slice(ret.as_slice()));
24+
push!(runtime, H256::from_slice(ret.as_ref()));
2525

2626
Control::Continue
2727
}
@@ -324,7 +324,7 @@ pub fn create<H: Handler>(runtime: &mut Runtime, is_create2: bool, handler: &mut
324324

325325
let scheme = if is_create2 {
326326
pop!(runtime, salt);
327-
let code_hash = H256::from_slice(Keccak256::digest(&code).as_slice());
327+
let code_hash = H256::from_slice(Keccak256::digest(&code).as_ref());
328328
CreateScheme::Create2 {
329329
caller: runtime.context.address,
330330
salt,

runtime/src/lib.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ pub struct Config {
306306
pub has_eip_7702: bool,
307307
/// Has EIP-7623. See [EIP-7623](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7623.md)
308308
pub has_eip_7623: bool,
309+
/// Has EIP-7939. See [EIP-7939](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-7939.md)
310+
pub has_eip_7939: bool,
309311
}
310312

311313
impl Config {
@@ -369,6 +371,7 @@ impl Config {
369371
has_eip_7623: false,
370372
gas_calldata_zero_floor: 0,
371373
gas_calldata_non_zero_floor: 0,
374+
has_eip_7939: false,
372375
}
373376
}
374377

@@ -432,6 +435,7 @@ impl Config {
432435
has_eip_7623: false,
433436
gas_calldata_zero_floor: 0,
434437
gas_calldata_non_zero_floor: 0,
438+
has_eip_7939: false,
435439
}
436440
}
437441

@@ -465,6 +469,11 @@ impl Config {
465469
Self::config_with_derived_values(DerivedConfigInputs::pectra())
466470
}
467471

472+
/// Osaka hard fork configuration.
473+
pub const fn osaka() -> Config {
474+
Self::config_with_derived_values(DerivedConfigInputs::osaka())
475+
}
476+
468477
const fn config_with_derived_values(inputs: DerivedConfigInputs) -> Config {
469478
let DerivedConfigInputs {
470479
gas_storage_read_warm,
@@ -485,6 +494,7 @@ impl Config {
485494
has_eip_7623,
486495
gas_calldata_zero_floor,
487496
gas_calldata_non_zero_floor,
497+
has_eip_7939,
488498
} = inputs;
489499

490500
// See https://eips.ethereum.org/EIPS/eip-2929
@@ -557,6 +567,7 @@ impl Config {
557567
has_eip_7623,
558568
gas_calldata_zero_floor,
559569
gas_calldata_non_zero_floor,
570+
has_eip_7939,
560571
}
561572
}
562573
}
@@ -582,6 +593,7 @@ struct DerivedConfigInputs {
582593
has_eip_7623: bool,
583594
gas_calldata_zero_floor: u64,
584595
gas_calldata_non_zero_floor: u64,
596+
has_eip_7939: bool,
585597
}
586598

587599
impl DerivedConfigInputs {
@@ -605,6 +617,7 @@ impl DerivedConfigInputs {
605617
has_eip_7623: false,
606618
gas_calldata_zero_floor: 0,
607619
gas_calldata_non_zero_floor: 0,
620+
has_eip_7939: false,
608621
}
609622
}
610623

@@ -628,6 +641,7 @@ impl DerivedConfigInputs {
628641
has_eip_7623: false,
629642
gas_calldata_zero_floor: 0,
630643
gas_calldata_non_zero_floor: 0,
644+
has_eip_7939: false,
631645
}
632646
}
633647

@@ -651,6 +665,7 @@ impl DerivedConfigInputs {
651665
has_eip_7623: false,
652666
gas_calldata_zero_floor: 0,
653667
gas_calldata_non_zero_floor: 0,
668+
has_eip_7939: false,
654669
}
655670
}
656671

@@ -675,6 +690,7 @@ impl DerivedConfigInputs {
675690
has_eip_7623: false,
676691
gas_calldata_zero_floor: 0,
677692
gas_calldata_non_zero_floor: 0,
693+
has_eip_7939: false,
678694
}
679695
}
680696

@@ -699,6 +715,7 @@ impl DerivedConfigInputs {
699715
has_eip_7623: false,
700716
gas_calldata_zero_floor: 0,
701717
gas_calldata_non_zero_floor: 0,
718+
has_eip_7939: false,
702719
}
703720
}
704721

@@ -726,6 +743,35 @@ impl DerivedConfigInputs {
726743
has_eip_7623: true,
727744
gas_calldata_zero_floor: 10,
728745
gas_calldata_non_zero_floor: 40,
746+
has_eip_7939: false,
747+
}
748+
}
749+
750+
/// Osaka hard fork configuration.
751+
const fn osaka() -> Self {
752+
Self {
753+
gas_storage_read_warm: 100,
754+
gas_sload_cold: 2100,
755+
gas_access_list_storage_key: 1900,
756+
decrease_clears_refund: true,
757+
has_base_fee: true,
758+
has_push0: true,
759+
disallow_executable_format: true,
760+
warm_coinbase_address: true,
761+
// 2 * 24576 as per EIP-3860
762+
max_initcode_size: Some(0xC000),
763+
has_eip_6780: true,
764+
has_tloadstore: true,
765+
has_mcopy: true,
766+
has_eip_7702: true,
767+
// PER_AUTH_BASE_COST from EIP-7702
768+
gas_auth_base_cost: 12500,
769+
// PER_EMPTY_ACCOUNT_COST from EIP-7702
770+
gas_per_empty_account_cost: 25000,
771+
has_eip_7623: true,
772+
gas_calldata_zero_floor: 10,
773+
gas_calldata_non_zero_floor: 40,
774+
has_eip_7939: true,
729775
}
730776
}
731777
}

src/executor/stack/executor.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ pub trait StackState<'config>: Backend {
239239
/// can be customized to use a more performant approach that don't need to
240240
/// fetch the code.
241241
fn code_hash(&self, address: H160) -> H256 {
242-
H256::from_slice(Keccak256::digest(self.code(address)).as_slice())
242+
H256::from_slice(Keccak256::digest(self.code(address)).as_ref())
243243
}
244244

245245
fn record_external_operation(
@@ -540,7 +540,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet>
540540
}
541541
}
542542

543-
let code_hash = H256::from_slice(Keccak256::digest(&init_code).as_slice());
543+
let code_hash = H256::from_slice(Keccak256::digest(&init_code).as_ref());
544544
event!(TransactCreate2 {
545545
caller,
546546
value,
@@ -792,14 +792,14 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet>
792792
hasher.update(&caller[..]);
793793
hasher.update(&salt[..]);
794794
hasher.update(&code_hash[..]);
795-
H256::from_slice(hasher.finalize().as_slice()).into()
795+
H256::from_slice(hasher.finalize().as_ref()).into()
796796
}
797797
CreateScheme::Legacy { caller } => {
798798
let nonce = self.nonce(caller);
799799
let mut stream = rlp::RlpStream::new_list(2);
800800
stream.append(&caller);
801801
stream.append(&nonce);
802-
H256::from_slice(Keccak256::digest(stream.out()).as_slice()).into()
802+
H256::from_slice(Keccak256::digest(stream.out()).as_ref()).into()
803803
}
804804
CreateScheme::Fixed(naddress) => naddress,
805805
}

0 commit comments

Comments
 (0)