diff --git a/evm/src/cpu/kernel/asm/core/exception.asm b/evm/src/cpu/kernel/asm/core/exception.asm index ae049434e6..05d8a25fed 100644 --- a/evm/src/cpu/kernel/asm/core/exception.asm +++ b/evm/src/cpu/kernel/asm/core/exception.asm @@ -211,7 +211,9 @@ min_stack_len_for_opcode: BYTES 0 // 0x46, CHAINID BYTES 0 // 0x47, SELFBALANCE BYTES 0 // 0x48, BASEFEE - %rep 7 // 0x49-0x4f, invalid + BYTES 0 // 0x49, invalid + BYTES 0 // 0x4a, BLOBBASEFEE + %rep 5 // 0x4b-0x4f, invalid BYTES 0 %endrep diff --git a/evm/src/cpu/kernel/asm/core/syscall.asm b/evm/src/cpu/kernel/asm/core/syscall.asm index f2c9aea0da..9bfcb24543 100644 --- a/evm/src/cpu/kernel/asm/core/syscall.asm +++ b/evm/src/cpu/kernel/asm/core/syscall.asm @@ -69,8 +69,10 @@ global syscall_jumptable: JUMPTABLE sys_chainid JUMPTABLE sys_selfbalance JUMPTABLE sys_basefee - %rep 7 - JUMPTABLE panic // 0x49-0x4f are invalid opcodes + JUMPTABLE panic // 0x49 is invalid + JUMPTABLE sys_blobbasefee + %rep 5 + JUMPTABLE panic // 0x4b-0x4f are invalid opcodes %endrep // 0x50-0x5f diff --git a/evm/src/cpu/kernel/asm/memory/metadata.asm b/evm/src/cpu/kernel/asm/memory/metadata.asm index d5b4033d56..203fd06ce3 100644 --- a/evm/src/cpu/kernel/asm/memory/metadata.asm +++ b/evm/src/cpu/kernel/asm/memory/metadata.asm @@ -226,6 +226,10 @@ global sys_chainid: %mload_global_metadata(@GLOBAL_METADATA_BLOCK_BASE_FEE) %endmacro +%macro blobbasefee + %mload_global_metadata(@GLOBAL_METADATA_BLOCK_BLOB_BASE_FEE) +%endmacro + global sys_basefee: // stack: kexit_info %charge_gas_const(@GAS_BASE) @@ -235,6 +239,15 @@ global sys_basefee: SWAP1 EXIT_KERNEL +global sys_blobbasefee: + // stack: kexit_info + %charge_gas_const(@GAS_BASE) + // stack: kexit_info + %blobbasefee + // stack: blobbasefee, kexit_info + SWAP1 + EXIT_KERNEL + global sys_blockhash: // stack: kexit_info, block_number %charge_gas_const(@GAS_BLOCKHASH) diff --git a/evm/src/cpu/kernel/constants/exc_bitfields.rs b/evm/src/cpu/kernel/constants/exc_bitfields.rs index 6751d96332..ff0782b322 100644 --- a/evm/src/cpu/kernel/constants/exc_bitfields.rs +++ b/evm/src/cpu/kernel/constants/exc_bitfields.rs @@ -36,6 +36,7 @@ pub const STACK_LENGTH_INCREASING_OPCODES_USER: U256 = u256_from_set_index_range 0x3a..=0x3a, // GASPRICE 0x3d..=0x3d, // RETURNDATASIZE 0x41..=0x48, // COINBASE, TIMESTAMP, NUMBER, DIFFICULTY, GASLIMIT, CHAINID, SELFBALANCE, BASEFEE + 0x4a..=0x4a, // BLOBBASEFEE 0x58..=0x5a, // PC, MSIZE, GAS 0x5f..=0x8f, // PUSH*, DUP* ]); diff --git a/evm/src/cpu/kernel/constants/global_metadata.rs b/evm/src/cpu/kernel/constants/global_metadata.rs index ad685222de..b3d9600d57 100644 --- a/evm/src/cpu/kernel/constants/global_metadata.rs +++ b/evm/src/cpu/kernel/constants/global_metadata.rs @@ -85,10 +85,11 @@ pub(crate) enum GlobalMetadata { LogsPayloadLen = 43, TxnNumberBefore = 44, TxnNumberAfter = 45, + BlockBlobBaseFee = 46, } impl GlobalMetadata { - pub(crate) const COUNT: usize = 46; + pub(crate) const COUNT: usize = 47; pub(crate) fn all() -> [Self; Self::COUNT] { [ @@ -138,6 +139,7 @@ impl GlobalMetadata { Self::BlockCurrentHash, Self::TxnNumberBefore, Self::TxnNumberAfter, + Self::BlockBlobBaseFee, ] } @@ -190,6 +192,7 @@ impl GlobalMetadata { Self::LogsPayloadLen => "GLOBAL_METADATA_LOGS_PAYLOAD_LEN", Self::TxnNumberBefore => "GLOBAL_METADATA_TXN_NUMBER_BEFORE", Self::TxnNumberAfter => "GLOBAL_METADATA_TXN_NUMBER_AFTER", + Self::BlockBlobBaseFee => "GLOBAL_METADATA_BLOCK_BLOB_BASE_FEE", } } } diff --git a/evm/src/cpu/kernel/interpreter.rs b/evm/src/cpu/kernel/interpreter.rs index 9df47248ed..e5ad9537bf 100644 --- a/evm/src/cpu/kernel/interpreter.rs +++ b/evm/src/cpu/kernel/interpreter.rs @@ -391,6 +391,7 @@ impl<'a> Interpreter<'a> { 0x46 => self.run_chainid(), // "CHAINID", 0x48 => self.run_basefee(), // "BASEFEE", 0x49 => self.run_prover_input()?, // "PROVER_INPUT", + 0x4a => self.run_blobbasefee(), // "BLOBBASEFEE", 0x50 => self.run_pop(), // "POP", 0x51 => self.run_mload(), // "MLOAD", 0x52 => self.run_mstore(), // "MSTORE", @@ -950,6 +951,10 @@ impl<'a> Interpreter<'a> { Ok(()) } + fn run_blobbasefee(&mut self) { + self.push(self.get_global_metadata_field(GlobalMetadata::BlockBlobBaseFee)) + } + fn run_pop(&mut self) { self.pop(); } @@ -1300,6 +1305,7 @@ fn get_mnemonic(opcode: u8) -> &'static str { 0x46 => "CHAINID", 0x48 => "BASEFEE", 0x49 => "PROVER_INPUT", + 0x4a => "BLOBBASEFEE", 0x50 => "POP", 0x51 => "MLOAD", 0x52 => "MSTORE", diff --git a/evm/src/cpu/kernel/opcodes.rs b/evm/src/cpu/kernel/opcodes.rs index b8732079e0..7f11765932 100644 --- a/evm/src/cpu/kernel/opcodes.rs +++ b/evm/src/cpu/kernel/opcodes.rs @@ -64,6 +64,7 @@ pub fn get_opcode(mnemonic: &str) -> u8 { "CHAINID" => 0x46, "BASEFEE" => 0x48, "PROVER_INPUT" => 0x49, + "BLOBBASEFEE" => 0x4a, "POP" => 0x50, "MLOAD" => 0x51, "MSTORE" => 0x52, diff --git a/evm/src/generation/mod.rs b/evm/src/generation/mod.rs index 62182cd254..49c0aebaff 100644 --- a/evm/src/generation/mod.rs +++ b/evm/src/generation/mod.rs @@ -115,6 +115,10 @@ fn apply_metadata_and_tries_memops, const D: usize> h2u(inputs.block_hashes.cur_hash), ), (GlobalMetadata::BlockGasUsed, metadata.block_gas_used), + ( + GlobalMetadata::BlockBlobBaseFee, + metadata.block_blob_base_fee, + ), (GlobalMetadata::BlockGasUsedBefore, inputs.gas_used_before), (GlobalMetadata::BlockGasUsedAfter, inputs.gas_used_after), (GlobalMetadata::TxnNumberBefore, inputs.txn_number_before), diff --git a/evm/src/proof.rs b/evm/src/proof.rs index 43561e8c8b..88ca27167b 100644 --- a/evm/src/proof.rs +++ b/evm/src/proof.rs @@ -107,6 +107,8 @@ pub struct BlockMetadata { pub block_base_fee: U256, /// The total gas used in this block. It must fit in a `u64`. pub block_gas_used: U256, + /// The blob base fee. It must fit in a `u64`. + pub block_blob_base_fee: U256, /// The block bloom of this block, represented as the consecutive /// 32-byte chunks of a block's final bloom filter string. pub block_bloom: [U256; 8], @@ -180,6 +182,7 @@ impl PublicValuesTarget { block_chain_id, block_base_fee, block_gas_used, + block_blob_base_fee, block_bloom, } = self.block_metadata; @@ -192,6 +195,7 @@ impl PublicValuesTarget { buffer.write_target(block_chain_id)?; buffer.write_target_array(&block_base_fee)?; buffer.write_target_array(&block_gas_used)?; + buffer.write_target_array(&block_blob_base_fee)?; buffer.write_target_array(&block_bloom)?; let BlockHashesTarget { @@ -244,6 +248,7 @@ impl PublicValuesTarget { block_chain_id: buffer.read_target()?, block_base_fee: buffer.read_target_array()?, block_gas_used: buffer.read_target_array()?, + block_blob_base_fee: buffer.read_target_array()?, block_bloom: buffer.read_target_array()?, }; @@ -418,11 +423,12 @@ pub struct BlockMetadataTarget { pub block_chain_id: Target, pub block_base_fee: [Target; 2], pub block_gas_used: [Target; 2], + pub block_blob_base_fee: [Target; 2], pub block_bloom: [Target; 64], } impl BlockMetadataTarget { - pub const SIZE: usize = 87; + pub const SIZE: usize = 89; pub fn from_public_inputs(pis: &[Target]) -> Self { let block_beneficiary = pis[0..5].try_into().unwrap(); @@ -434,7 +440,8 @@ impl BlockMetadataTarget { let block_chain_id = pis[18]; let block_base_fee = pis[19..21].try_into().unwrap(); let block_gas_used = pis[21..23].try_into().unwrap(); - let block_bloom = pis[23..87].try_into().unwrap(); + let block_blob_base_fee = pis[23..25].try_into().unwrap(); + let block_bloom = pis[25..89].try_into().unwrap(); Self { block_beneficiary, @@ -446,6 +453,7 @@ impl BlockMetadataTarget { block_chain_id, block_base_fee, block_gas_used, + block_blob_base_fee, block_bloom, } } @@ -480,6 +488,13 @@ impl BlockMetadataTarget { block_gas_used: core::array::from_fn(|i| { builder.select(condition, bm0.block_gas_used[i], bm1.block_gas_used[i]) }), + block_blob_base_fee: core::array::from_fn(|i| { + builder.select( + condition, + bm0.block_blob_base_fee[i], + bm1.block_blob_base_fee[i], + ) + }), block_bloom: core::array::from_fn(|i| { builder.select(condition, bm0.block_bloom[i], bm1.block_bloom[i]) }), @@ -510,6 +525,9 @@ impl BlockMetadataTarget { for i in 0..2 { builder.connect(bm0.block_gas_used[i], bm1.block_gas_used[i]) } + for i in 0..2 { + builder.connect(bm0.block_blob_base_fee[i], bm1.block_blob_base_fee[i]) + } for i in 0..64 { builder.connect(bm0.block_bloom[i], bm1.block_bloom[i]) } diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 7464eb1715..9b294fc5ae 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -458,9 +458,9 @@ pub(crate) fn get_memory_extra_looking_products_circuit< ]; // This contains the `block_beneficiary`, `block_random`, `block_base_fee`, - // `block_gaslimit`, `block_gas_used` as well as `cur_hash`, `gas_used_before` - // and `gas_used_after`. - let block_fields_arrays: [(usize, &[Target]); 8] = [ + // `block_gaslimit`, `block_gas_used`, `block_blob_base_fee` as well as `cur_hash`, + // `gas_used_before` and `gas_used_after`. + let block_fields_arrays: [(usize, &[Target]); 9] = [ ( GlobalMetadata::BlockBeneficiary as usize, &public_values.block_metadata.block_beneficiary, @@ -481,6 +481,10 @@ pub(crate) fn get_memory_extra_looking_products_circuit< GlobalMetadata::BlockGasUsed as usize, &public_values.block_metadata.block_gas_used, ), + ( + GlobalMetadata::BlockBlobBaseFee as usize, + &public_values.block_metadata.block_blob_base_fee, + ), ( GlobalMetadata::BlockCurrentHash as usize, &public_values.block_hashes.cur_hash, @@ -708,6 +712,7 @@ pub(crate) fn add_virtual_block_metadata, const D: let block_chain_id = builder.add_virtual_public_input(); let block_base_fee = builder.add_virtual_public_input_arr(); let block_gas_used = builder.add_virtual_public_input_arr(); + let block_blob_base_fee = builder.add_virtual_public_input_arr(); let block_bloom = builder.add_virtual_public_input_arr(); BlockMetadataTarget { block_beneficiary, @@ -719,6 +724,7 @@ pub(crate) fn add_virtual_block_metadata, const D: block_chain_id, block_base_fee, block_gas_used, + block_blob_base_fee, block_bloom, } } @@ -969,6 +975,10 @@ where let gas_used = u256_to_u64(block_metadata.block_gas_used)?; witness.set_target(block_metadata_target.block_gas_used[0], gas_used.0); witness.set_target(block_metadata_target.block_gas_used[1], gas_used.1); + // Blobbasefee fits in 2 limbs + let blob_basefee = u256_to_u64(block_metadata.block_blob_base_fee)?; + witness.set_target(block_metadata_target.block_blob_base_fee[0], blob_basefee.0); + witness.set_target(block_metadata_target.block_blob_base_fee[1], blob_basefee.1); let mut block_bloom_limbs = [F::ZERO; 64]; for (i, limbs) in block_bloom_limbs.chunks_exact_mut(8).enumerate() { limbs.copy_from_slice(&u256_limbs(block_metadata.block_bloom[i])); diff --git a/evm/src/verifier.rs b/evm/src/verifier.rs index 04450b4606..919528f189 100644 --- a/evm/src/verifier.rs +++ b/evm/src/verifier.rs @@ -194,6 +194,10 @@ where GlobalMetadata::BlockGasUsed, public_values.block_metadata.block_gas_used, ), + ( + GlobalMetadata::BlockBlobBaseFee, + public_values.block_metadata.block_blob_base_fee, + ), ( GlobalMetadata::TxnNumberBefore, public_values.extra_block_data.txn_number_before, @@ -509,6 +513,10 @@ pub(crate) mod testutils { GlobalMetadata::BlockGasUsed, public_values.block_metadata.block_gas_used, ), + ( + GlobalMetadata::BlockBlobBaseFee, + public_values.block_metadata.block_blob_base_fee, + ), ( GlobalMetadata::TxnNumberBefore, public_values.extra_block_data.txn_number_before, diff --git a/evm/src/witness/transition.rs b/evm/src/witness/transition.rs index 79a07bd25c..abc398e644 100644 --- a/evm/src/witness/transition.rs +++ b/evm/src/witness/transition.rs @@ -107,6 +107,7 @@ fn decode(registers: RegistersState, opcode: u8) -> Result Ok(Operation::Syscall(opcode, 0, true)), // SELFBALANCE (0x48, _) => Ok(Operation::Syscall(opcode, 0, true)), // BASEFEE (0x49, true) => Ok(Operation::ProverInput), + (0x4a, _) => Ok(Operation::Syscall(opcode, 0, true)), // BLOBBASEFEE (0x50, _) => Ok(Operation::Pop), (0x51, _) => Ok(Operation::Syscall(opcode, 1, false)), // MLOAD (0x52, _) => Ok(Operation::Syscall(opcode, 2, false)), // MSTORE diff --git a/evm/tests/add11_yml.rs b/evm/tests/add11_yml.rs index cb0212a388..91db589358 100644 --- a/evm/tests/add11_yml.rs +++ b/evm/tests/add11_yml.rs @@ -88,6 +88,7 @@ fn add11_yml() -> anyhow::Result<()> { block_chain_id: 1.into(), block_base_fee: 0xa.into(), block_gas_used: 0xa868u64.into(), + block_blob_base_fee: 0x2.into(), block_bloom: [0.into(); 8], }; diff --git a/evm/tests/basic_smart_contract.rs b/evm/tests/basic_smart_contract.rs index 687328dcb9..dcfd2b1bf9 100644 --- a/evm/tests/basic_smart_contract.rs +++ b/evm/tests/basic_smart_contract.rs @@ -115,6 +115,7 @@ fn test_basic_smart_contract() -> anyhow::Result<()> { block_gas_used: gas_used.into(), block_bloom: [0.into(); 8], block_base_fee: 0xa.into(), + block_blob_base_fee: 0x2.into(), block_random: Default::default(), }; diff --git a/evm/tests/log_opcode.rs b/evm/tests/log_opcode.rs index dd7ea223e4..21bc56c48d 100644 --- a/evm/tests/log_opcode.rs +++ b/evm/tests/log_opcode.rs @@ -141,6 +141,7 @@ fn test_log_opcodes() -> anyhow::Result<()> { block_chain_id: 1.into(), block_base_fee: 0xa.into(), block_gas_used: 0.into(), + block_blob_base_fee: 0x2.into(), block_bloom: [0.into(); 8], }; @@ -359,6 +360,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { block_chain_id: 1.into(), block_base_fee: 0xa.into(), block_gas_used: (22570 + 21000).into(), + block_blob_base_fee: 0x2.into(), block_bloom: [ 0.into(), 0.into(), @@ -818,6 +820,7 @@ fn test_two_txn() -> anyhow::Result<()> { block_chain_id: 1.into(), block_base_fee: 0xa.into(), block_gas_used: 0.into(), + block_blob_base_fee: 0x2.into(), block_bloom: [0.into(); 8], }; diff --git a/evm/tests/self_balance_gas_cost.rs b/evm/tests/self_balance_gas_cost.rs index 4492ba9af4..6da44ef452 100644 --- a/evm/tests/self_balance_gas_cost.rs +++ b/evm/tests/self_balance_gas_cost.rs @@ -104,6 +104,7 @@ fn self_balance_gas_cost() -> anyhow::Result<()> { block_gas_used: gas_used.into(), block_bloom: [0.into(); 8], block_base_fee: 0xa.into(), + block_blob_base_fee: 0x2.into(), block_random: Default::default(), }; diff --git a/evm/tests/simple_transfer.rs b/evm/tests/simple_transfer.rs index 80bee8afeb..ccf91d4a26 100644 --- a/evm/tests/simple_transfer.rs +++ b/evm/tests/simple_transfer.rs @@ -77,6 +77,7 @@ fn test_simple_transfer() -> anyhow::Result<()> { block_chain_id: 1.into(), block_base_fee: 0xa.into(), block_gas_used: 21032.into(), + block_blob_base_fee: 0x2.into(), block_bloom: [0.into(); 8], };