diff --git a/evm/src/cpu/kernel/aggregator.rs b/evm/src/cpu/kernel/aggregator.rs index 160702df74..0c7c657999 100644 --- a/evm/src/cpu/kernel/aggregator.rs +++ b/evm/src/cpu/kernel/aggregator.rs @@ -36,7 +36,6 @@ pub(crate) fn combined_kernel() -> Kernel { include_str!("asm/core/nonce.asm"), include_str!("asm/core/process_txn.asm"), include_str!("asm/core/syscall.asm"), - include_str!("asm/core/syscall_stubs.asm"), include_str!("asm/core/terminate.asm"), include_str!("asm/core/transfer.asm"), include_str!("asm/core/util.asm"), diff --git a/evm/src/cpu/kernel/asm/core/syscall_stubs.asm b/evm/src/cpu/kernel/asm/core/syscall_stubs.asm deleted file mode 100644 index 70a64b87da..0000000000 --- a/evm/src/cpu/kernel/asm/core/syscall_stubs.asm +++ /dev/null @@ -1,12 +0,0 @@ -// Labels for unimplemented syscalls to make the kernel assemble. -// Each label should be removed from this file once it is implemented. - -// This is a temporary version that returns the block difficulty (i.e. the old version of this opcode). -// TODO: Fix this. -// TODO: What semantics will this have for Edge? -global sys_prevrandao: - // stack: kexit_info - %charge_gas_const(@GAS_BASE) - %mload_global_metadata(@GLOBAL_METADATA_BLOCK_DIFFICULTY) - %stack (difficulty, kexit_info) -> (kexit_info, difficulty) - EXIT_KERNEL diff --git a/evm/src/cpu/kernel/asm/memory/metadata.asm b/evm/src/cpu/kernel/asm/memory/metadata.asm index 5b1417da79..c26d3d5fb9 100644 --- a/evm/src/cpu/kernel/asm/memory/metadata.asm +++ b/evm/src/cpu/kernel/asm/memory/metadata.asm @@ -383,3 +383,10 @@ zero_hash: %decrement %mstore_global_metadata(@GLOBAL_METADATA_CALL_STACK_DEPTH) %endmacro + +global sys_prevrandao: + // stack: kexit_info + %charge_gas_const(@GAS_BASE) + %mload_global_metadata(@GLOBAL_METADATA_BLOCK_RANDOM) + %stack (random, kexit_info) -> (kexit_info, random) + EXIT_KERNEL diff --git a/evm/src/cpu/kernel/constants/global_metadata.rs b/evm/src/cpu/kernel/constants/global_metadata.rs index 01f7d0dc32..ad685222de 100644 --- a/evm/src/cpu/kernel/constants/global_metadata.rs +++ b/evm/src/cpu/kernel/constants/global_metadata.rs @@ -39,55 +39,56 @@ pub(crate) enum GlobalMetadata { BlockTimestamp = 15, BlockNumber = 16, BlockDifficulty = 17, - BlockGasLimit = 18, - BlockChainId = 19, - BlockBaseFee = 20, - BlockGasUsed = 21, + BlockRandom = 18, + BlockGasLimit = 19, + BlockChainId = 20, + BlockBaseFee = 21, + BlockGasUsed = 22, /// Before current transactions block values. - BlockGasUsedBefore = 22, + BlockGasUsedBefore = 23, /// After current transactions block values. - BlockGasUsedAfter = 23, + BlockGasUsedAfter = 24, /// Current block header hash - BlockCurrentHash = 24, + BlockCurrentHash = 25, /// Gas to refund at the end of the transaction. - RefundCounter = 25, + RefundCounter = 26, /// Length of the addresses access list. - AccessedAddressesLen = 26, + AccessedAddressesLen = 27, /// Length of the storage keys access list. - AccessedStorageKeysLen = 27, + AccessedStorageKeysLen = 28, /// Length of the self-destruct list. - SelfDestructListLen = 28, + SelfDestructListLen = 29, /// Length of the bloom entry buffer. - BloomEntryLen = 29, + BloomEntryLen = 30, /// Length of the journal. - JournalLen = 30, + JournalLen = 31, /// Length of the `JournalData` segment. - JournalDataLen = 31, + JournalDataLen = 32, /// Current checkpoint. - CurrentCheckpoint = 32, - TouchedAddressesLen = 33, + CurrentCheckpoint = 33, + TouchedAddressesLen = 34, // Gas cost for the access list in type-1 txns. See EIP-2930. - AccessListDataCost = 34, + AccessListDataCost = 35, // Start of the access list in the RLP for type-1 txns. - AccessListRlpStart = 35, + AccessListRlpStart = 36, // Length of the access list in the RLP for type-1 txns. - AccessListRlpLen = 36, + AccessListRlpLen = 37, // Boolean flag indicating if the txn is a contract creation txn. - ContractCreation = 37, - IsPrecompileFromEoa = 38, - CallStackDepth = 39, + ContractCreation = 38, + IsPrecompileFromEoa = 39, + CallStackDepth = 40, /// Transaction logs list length - LogsLen = 40, - LogsDataLen = 41, - LogsPayloadLen = 42, - TxnNumberBefore = 43, - TxnNumberAfter = 44, + LogsLen = 41, + LogsDataLen = 42, + LogsPayloadLen = 43, + TxnNumberBefore = 44, + TxnNumberAfter = 45, } impl GlobalMetadata { - pub(crate) const COUNT: usize = 45; + pub(crate) const COUNT: usize = 46; pub(crate) fn all() -> [Self; Self::COUNT] { [ @@ -109,6 +110,7 @@ impl GlobalMetadata { Self::BlockTimestamp, Self::BlockNumber, Self::BlockDifficulty, + Self::BlockRandom, Self::BlockGasLimit, Self::BlockChainId, Self::BlockBaseFee, @@ -160,6 +162,7 @@ impl GlobalMetadata { Self::BlockTimestamp => "GLOBAL_METADATA_BLOCK_TIMESTAMP", Self::BlockNumber => "GLOBAL_METADATA_BLOCK_NUMBER", Self::BlockDifficulty => "GLOBAL_METADATA_BLOCK_DIFFICULTY", + Self::BlockRandom => "GLOBAL_METADATA_BLOCK_RANDOM", Self::BlockGasLimit => "GLOBAL_METADATA_BLOCK_GAS_LIMIT", Self::BlockChainId => "GLOBAL_METADATA_BLOCK_CHAIN_ID", Self::BlockBaseFee => "GLOBAL_METADATA_BLOCK_BASE_FEE", diff --git a/evm/src/generation/mod.rs b/evm/src/generation/mod.rs index 35078e0784..3f5bafba1e 100644 --- a/evm/src/generation/mod.rs +++ b/evm/src/generation/mod.rs @@ -100,6 +100,10 @@ fn apply_metadata_and_tries_memops, const D: usize> (GlobalMetadata::BlockTimestamp, metadata.block_timestamp), (GlobalMetadata::BlockNumber, metadata.block_number), (GlobalMetadata::BlockDifficulty, metadata.block_difficulty), + ( + GlobalMetadata::BlockRandom, + metadata.block_random.into_uint(), + ), (GlobalMetadata::BlockGasLimit, metadata.block_gaslimit), (GlobalMetadata::BlockChainId, metadata.block_chain_id), (GlobalMetadata::BlockBaseFee, metadata.block_base_fee), diff --git a/evm/src/get_challenges.rs b/evm/src/get_challenges.rs index ab25a28d57..1d2ae6029d 100644 --- a/evm/src/get_challenges.rs +++ b/evm/src/get_challenges.rs @@ -65,6 +65,7 @@ fn observe_block_metadata< challenger.observe_element(u256_to_u32(block_metadata.block_number)?); challenger.observe_element(u256_to_u32(block_metadata.block_difficulty)?); challenger.observe_element(u256_to_u32(block_metadata.block_gaslimit)?); + challenger.observe_elements(&h256_limbs::(block_metadata.block_random)); challenger.observe_element(u256_to_u32(block_metadata.block_chain_id)?); let basefee = u256_to_u64(block_metadata.block_base_fee)?; challenger.observe_element(basefee.0); @@ -91,6 +92,7 @@ fn observe_block_metadata_target< challenger.observe_element(block_metadata.block_timestamp); challenger.observe_element(block_metadata.block_number); challenger.observe_element(block_metadata.block_difficulty); + challenger.observe_elements(&block_metadata.block_random); challenger.observe_element(block_metadata.block_gaslimit); challenger.observe_element(block_metadata.block_chain_id); challenger.observe_elements(&block_metadata.block_base_fee); diff --git a/evm/src/proof.rs b/evm/src/proof.rs index 4da5ad23ab..03e520ca6a 100644 --- a/evm/src/proof.rs +++ b/evm/src/proof.rs @@ -101,6 +101,7 @@ pub struct BlockMetadata { pub block_number: U256, /// The difficulty (before PoS transition) of this block. pub block_difficulty: U256, + pub block_random: H256, /// The gas limit of this block. It must fit in a `u32`. pub block_gaslimit: U256, /// The chain id of this block. @@ -175,6 +176,7 @@ impl PublicValuesTarget { block_timestamp, block_number, block_difficulty, + block_random, block_gaslimit, block_chain_id, block_base_fee, @@ -186,6 +188,7 @@ impl PublicValuesTarget { buffer.write_target(block_timestamp)?; buffer.write_target(block_number)?; buffer.write_target(block_difficulty)?; + buffer.write_target_array(&block_random)?; buffer.write_target(block_gaslimit)?; buffer.write_target(block_chain_id)?; buffer.write_target_array(&block_base_fee)?; @@ -235,6 +238,7 @@ impl PublicValuesTarget { block_timestamp: buffer.read_target()?, block_number: buffer.read_target()?, block_difficulty: buffer.read_target()?, + block_random: buffer.read_target_array()?, block_gaslimit: buffer.read_target()?, block_chain_id: buffer.read_target()?, block_base_fee: buffer.read_target_array()?, @@ -407,6 +411,7 @@ pub struct BlockMetadataTarget { pub block_timestamp: Target, pub block_number: Target, pub block_difficulty: Target, + pub block_random: [Target; 8], pub block_gaslimit: Target, pub block_chain_id: Target, pub block_base_fee: [Target; 2], @@ -415,24 +420,26 @@ pub struct BlockMetadataTarget { } impl BlockMetadataTarget { - const SIZE: usize = 77; + const SIZE: usize = 85; pub fn from_public_inputs(pis: &[Target]) -> Self { let block_beneficiary = pis[0..5].try_into().unwrap(); let block_timestamp = pis[5]; let block_number = pis[6]; let block_difficulty = pis[7]; - let block_gaslimit = pis[8]; - let block_chain_id = pis[9]; - let block_base_fee = pis[10..12].try_into().unwrap(); - let block_gas_used = pis[12]; - let block_bloom = pis[13..77].try_into().unwrap(); + let block_random = pis[8..16].try_into().unwrap(); + let block_gaslimit = pis[16]; + let block_chain_id = pis[17]; + let block_base_fee = pis[18..20].try_into().unwrap(); + let block_gas_used = pis[20]; + let block_bloom = pis[21..85].try_into().unwrap(); Self { block_beneficiary, block_timestamp, block_number, block_difficulty, + block_random, block_gaslimit, block_chain_id, block_base_fee, @@ -458,6 +465,9 @@ impl BlockMetadataTarget { block_timestamp: builder.select(condition, bm0.block_timestamp, bm1.block_timestamp), block_number: builder.select(condition, bm0.block_number, bm1.block_number), block_difficulty: builder.select(condition, bm0.block_difficulty, bm1.block_difficulty), + block_random: core::array::from_fn(|i| { + builder.select(condition, bm0.block_random[i], bm1.block_random[i]) + }), block_gaslimit: builder.select(condition, bm0.block_gaslimit, bm1.block_gaslimit), block_chain_id: builder.select(condition, bm0.block_chain_id, bm1.block_chain_id), block_base_fee: core::array::from_fn(|i| { @@ -481,6 +491,9 @@ impl BlockMetadataTarget { builder.connect(bm0.block_timestamp, bm1.block_timestamp); builder.connect(bm0.block_number, bm1.block_number); builder.connect(bm0.block_difficulty, bm1.block_difficulty); + for i in 0..8 { + builder.connect(bm0.block_random[i], bm1.block_random[i]); + } builder.connect(bm0.block_gaslimit, bm1.block_gaslimit); builder.connect(bm0.block_chain_id, bm1.block_chain_id); for i in 0..2 { diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index f4e76c3931..1457344c52 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -548,11 +548,15 @@ pub(crate) fn get_memory_extra_looking_products_circuit< ), ]; - let beneficiary_base_fee_cur_hash_fields: [(usize, &[Target]); 3] = [ + let beneficiary_random_base_fee_cur_hash_fields: [(usize, &[Target]); 4] = [ ( GlobalMetadata::BlockBeneficiary as usize, &public_values.block_metadata.block_beneficiary, ), + ( + GlobalMetadata::BlockRandom as usize, + &public_values.block_metadata.block_random, + ), ( GlobalMetadata::BlockBaseFee as usize, &public_values.block_metadata.block_base_fee, @@ -576,7 +580,7 @@ pub(crate) fn get_memory_extra_looking_products_circuit< ); }); - beneficiary_base_fee_cur_hash_fields.map(|(field, targets)| { + beneficiary_random_base_fee_cur_hash_fields.map(|(field, targets)| { product = add_data_write( builder, challenge, @@ -772,6 +776,7 @@ pub(crate) fn add_virtual_block_metadata, const D: let block_timestamp = builder.add_virtual_public_input(); let block_number = builder.add_virtual_public_input(); let block_difficulty = builder.add_virtual_public_input(); + let block_random = builder.add_virtual_public_input_arr(); let block_gaslimit = builder.add_virtual_public_input(); let block_chain_id = builder.add_virtual_public_input(); let block_base_fee = builder.add_virtual_public_input_arr(); @@ -782,6 +787,7 @@ pub(crate) fn add_virtual_block_metadata, const D: block_timestamp, block_number, block_difficulty, + block_random, block_gaslimit, block_chain_id, block_base_fee, @@ -1014,6 +1020,10 @@ where block_metadata_target.block_difficulty, u256_to_u32(block_metadata.block_difficulty)?, ); + witness.set_target_arr( + &block_metadata_target.block_random, + &h256_limbs(block_metadata.block_random), + ); witness.set_target( block_metadata_target.block_gaslimit, u256_to_u32(block_metadata.block_gaslimit)?, diff --git a/evm/src/verifier.rs b/evm/src/verifier.rs index c7b58060fb..96ef286061 100644 --- a/evm/src/verifier.rs +++ b/evm/src/verifier.rs @@ -1,7 +1,7 @@ use std::any::type_name; use anyhow::{ensure, Result}; -use ethereum_types::U256; +use ethereum_types::{BigEndianHash, U256}; use itertools::Itertools; use plonky2::field::extension::{Extendable, FieldExtension}; use plonky2::field::types::Field; @@ -157,6 +157,10 @@ where GlobalMetadata::BlockNumber, public_values.block_metadata.block_number, ), + ( + GlobalMetadata::BlockRandom, + public_values.block_metadata.block_random.into_uint(), + ), ( GlobalMetadata::BlockDifficulty, public_values.block_metadata.block_difficulty, diff --git a/evm/tests/add11_yml.rs b/evm/tests/add11_yml.rs index f628e94441..a456f02d0c 100644 --- a/evm/tests/add11_yml.rs +++ b/evm/tests/add11_yml.rs @@ -5,7 +5,7 @@ use std::time::Duration; use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use eth_trie_utils::nibbles::Nibbles; use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; -use ethereum_types::{Address, H256}; +use ethereum_types::{Address, BigEndianHash, H256}; use hex_literal::hex; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; @@ -83,6 +83,7 @@ fn add11_yml() -> anyhow::Result<()> { block_timestamp: 0x03e8.into(), block_number: 1.into(), block_difficulty: 0x020000.into(), + block_random: H256::from_uint(&0x020000.into()), block_gaslimit: 0xff112233u32.into(), block_chain_id: 1.into(), block_base_fee: 0xa.into(), diff --git a/evm/tests/basic_smart_contract.rs b/evm/tests/basic_smart_contract.rs index 2cd549ff9e..0130c6feb2 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_random: Default::default(), }; let mut contract_code = HashMap::new(); diff --git a/evm/tests/log_opcode.rs b/evm/tests/log_opcode.rs index 16d83bd06e..67407807ae 100644 --- a/evm/tests/log_opcode.rs +++ b/evm/tests/log_opcode.rs @@ -8,7 +8,7 @@ use bytes::Bytes; use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use eth_trie_utils::nibbles::Nibbles; use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; -use ethereum_types::{Address, H256, U256}; +use ethereum_types::{Address, BigEndianHash, H256, U256}; use hex_literal::hex; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; @@ -135,6 +135,7 @@ fn test_log_opcodes() -> anyhow::Result<()> { block_timestamp: 0x03e8.into(), block_number: 1.into(), block_difficulty: 0x020000.into(), + block_random: H256::from_uint(&0x020000.into()), block_gaslimit: 0xffffffffu32.into(), block_chain_id: 1.into(), block_base_fee: 0xa.into(), @@ -365,6 +366,7 @@ fn test_log_with_aggreg() -> anyhow::Result<()> { .unwrap(), U256::from_dec_str("2722259584404615024560450425766186844160").unwrap(), ], + block_random: Default::default(), }; let beneficiary_account_after = AccountRlp { @@ -791,6 +793,7 @@ fn test_two_txn() -> anyhow::Result<()> { block_timestamp: 0x03e8.into(), block_number: 1.into(), block_difficulty: 0x020000.into(), + block_random: H256::from_uint(&0x020000.into()), block_gaslimit: 0xffffffffu32.into(), block_chain_id: 1.into(), block_base_fee: 0xa.into(), diff --git a/evm/tests/self_balance_gas_cost.rs b/evm/tests/self_balance_gas_cost.rs index 9ba1ac5497..de16db944a 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_random: Default::default(), }; let mut contract_code = HashMap::new(); diff --git a/evm/tests/simple_transfer.rs b/evm/tests/simple_transfer.rs index b8c47fe9a6..268ad6615d 100644 --- a/evm/tests/simple_transfer.rs +++ b/evm/tests/simple_transfer.rs @@ -5,7 +5,7 @@ use std::time::Duration; use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use eth_trie_utils::nibbles::Nibbles; use eth_trie_utils::partial_trie::{HashedPartialTrie, PartialTrie}; -use ethereum_types::{Address, H256, U256}; +use ethereum_types::{Address, BigEndianHash, H256, U256}; use hex_literal::hex; use keccak_hash::keccak; use plonky2::field::goldilocks_field::GoldilocksField; @@ -71,6 +71,7 @@ fn test_simple_transfer() -> anyhow::Result<()> { block_timestamp: 0x03e8.into(), block_number: 1.into(), block_difficulty: 0x020000.into(), + block_random: H256::from_uint(&0x020000.into()), block_gaslimit: 0xff112233u32.into(), block_chain_id: 1.into(), block_base_fee: 0xa.into(),