diff --git a/examples/demo-rollup/tests/evm/mod.rs b/examples/demo-rollup/tests/evm/mod.rs index 952174e7a..cdbcd1111 100644 --- a/examples/demo-rollup/tests/evm/mod.rs +++ b/examples/demo-rollup/tests/evm/mod.rs @@ -5,7 +5,7 @@ use ethereum_types::H160; use ethers_core::abi::Address; use ethers_core::k256::ecdsa::SigningKey; use ethers_core::types::transaction::eip2718::TypedTransaction; -use ethers_core::types::Eip1559TransactionRequest; +use ethers_core::types::{Block, Eip1559TransactionRequest, Transaction, TxHash}; use ethers_middleware::SignerMiddleware; use ethers_providers::{Http, Middleware, PendingTransaction, Provider}; use ethers_signers::{LocalWallet, Signer, Wallet}; @@ -146,6 +146,23 @@ impl TestClient { chain_id.as_u64() } + async fn eth_get_block_by_number(&self, block_number: Option) -> Block { + self.http_client + .request("eth_getBlockByNumber", rpc_params![block_number, false]) + .await + .unwrap() + } + + async fn eth_get_block_by_number_with_detail( + &self, + block_number: Option, + ) -> Block { + self.http_client + .request("eth_getBlockByNumber", rpc_params![block_number, true]) + .await + .unwrap() + } + async fn execute(self) -> Result<(), Box> { let contract_address = { let deploy_contract_req = self.deploy_contract().await?; @@ -158,18 +175,32 @@ impl TestClient { .unwrap() }; + // Check that the first block has published + // It should have a single transaction, deploying the contract + let first_block = self.eth_get_block_by_number(Some("1".to_owned())).await; + assert_eq!(first_block.number.unwrap().as_u64(), 1); + assert_eq!(first_block.transactions.len(), 1); + let set_arg = 923; - { + let tx_hash = { let set_value_req = self.set_value(contract_address, set_arg, 1).await; self.send_publish_batch_request().await; - set_value_req.await.unwrap(); - } + set_value_req.await.unwrap().unwrap().transaction_hash + }; { let get_arg = self.query_contract(contract_address, 2).await?; assert_eq!(set_arg, get_arg.as_u32()); } + // Check that the second block has published + // None should return the latest block + // It should have a single transaction, setting the value + let latest_block = self.eth_get_block_by_number_with_detail(None).await; + assert_eq!(latest_block.number.unwrap().as_u64(), 2); + assert_eq!(latest_block.transactions.len(), 1); + assert_eq!(latest_block.transactions[0].hash, tx_hash); + // Create a blob with multiple transactions. let mut requests = Vec::default(); let mut nonce = 2; @@ -213,6 +244,17 @@ async fn send_tx_test_to_eth(rpc_address: SocketAddr) -> Result<(), Box Evm { + fn get_sealed_block_by_number( + &self, + block_number: Option, + working_set: &mut WorkingSet, + ) -> SealedBlock { + // safe, finalized, and pending are not supported + match block_number { + Some(ref block_number) if block_number == "earliest" => self + .blocks + .get(0, &mut working_set.accessory_state()) + .expect("Genesis block must be set"), + Some(ref block_number) if block_number == "latest" => self + .blocks + .last(&mut working_set.accessory_state()) + .expect("Head block must be set"), + Some(ref block_number) => { + let block_number = + usize::from_str_radix(block_number, 16).expect("Block number must be hex"); + self.blocks + .get(block_number, &mut working_set.accessory_state()) + .expect("Block must be set") + } + None => self + .blocks + .last(&mut working_set.accessory_state()) + .expect("Head block must be set"), + } + } + #[rpc_method(name = "chainId")] pub fn chain_id( &self, @@ -32,42 +61,63 @@ impl Evm { Ok(Some(chain_id)) } - // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/502 #[rpc_method(name = "getBlockByNumber")] pub fn get_block_by_number( &self, - _block_number: Option, - _details: Option, - _working_set: &mut WorkingSet, + block_number: Option, + details: Option, + working_set: &mut WorkingSet, ) -> RpcResult> { info!("evm module: eth_getBlockByNumber"); - let header = reth_rpc_types::Header { - hash: Default::default(), - parent_hash: Default::default(), - uncles_hash: Default::default(), - miner: Default::default(), - state_root: Default::default(), - transactions_root: Default::default(), - receipts_root: Default::default(), - logs_bloom: Default::default(), - difficulty: Default::default(), - number: Default::default(), - gas_limit: Default::default(), - gas_used: Default::default(), - timestamp: Default::default(), - extra_data: Default::default(), - mix_hash: Default::default(), - nonce: Default::default(), - base_fee_per_gas: Some(reth_primitives::U256::from(100)), - withdrawals_root: Default::default(), + let block = self.get_sealed_block_by_number(block_number, working_set); + + // Build rpc header response + let header = reth_rpc_types::Header::from_primitive_with_hash(block.header.clone()); + + // Collect transactions with ids from db + let transactions_with_ids = block + .transactions + .clone() + .map(|id| { + let tx = self + .transactions + .get(id as usize, &mut working_set.accessory_state()) + .expect("Transaction must be set"); + (id, tx) + }) + .collect::>(); + + // Build rpc transactions response + let transactions = match details { + Some(true) => reth_rpc_types::BlockTransactions::Full( + transactions_with_ids + .iter() + .map(|(id, tx)| { + reth_rpc_types::Transaction::from_recovered_with_block_context( + tx.clone().into(), + block.header.hash, + block.header.number, + block.header.base_fee_per_gas, + U256::from(id - block.transactions.start), + ) + }) + .collect::>(), + ), + _ => reth_rpc_types::BlockTransactions::Hashes({ + transactions_with_ids + .iter() + .map(|(_, tx)| tx.signed_transaction.hash) + .collect::>() + }), }; + // Build rpc block response let block = reth_rpc_types::Block { header, total_difficulty: Default::default(), uncles: Default::default(), - transactions: reth_rpc_types::BlockTransactions::Hashes(Default::default()), + transactions, size: Default::default(), withdrawals: Default::default(), };