diff --git a/bus-mapping/src/eth_types.rs b/bus-mapping/src/eth_types.rs index 92172f5a84..1021985684 100644 --- a/bus-mapping/src/eth_types.rs +++ b/bus-mapping/src/eth_types.rs @@ -4,8 +4,8 @@ use crate::evm::{memory::Memory, stack::Stack, storage::Storage}; use crate::evm::{Gas, GasCost, OpcodeId, ProgramCounter}; use ethers_core::types; pub use ethers_core::types::{ - transaction::response::Transaction, Address, Block, Bytes, H160, H256, - U256, U64, + transaction::response::Transaction, Address, Block, Bytes, + EIP1186ProofResponse, H160, H256, U256, U64, }; use pairing::arithmetic::FieldExt; use serde::{de, Deserialize}; diff --git a/bus-mapping/src/rpc.rs b/bus-mapping/src/rpc.rs index 6f35eb4294..d92b60fd53 100644 --- a/bus-mapping/src/rpc.rs +++ b/bus-mapping/src/rpc.rs @@ -2,7 +2,8 @@ //! query a Geth node in order to get a Block, Tx or Trace info. use crate::eth_types::{ - Block, GethExecTrace, Hash, ResultGethExecTraces, Transaction, U64, + Address, Block, EIP1186ProofResponse, GethExecTrace, Hash, + ResultGethExecTraces, Transaction, Word, U64, }; use crate::Error; use ethers_providers::JsonRpcClient; @@ -119,6 +120,24 @@ impl GethClient

{ .map_err(|e| Error::JSONRpcError(e.into()))?; Ok(resp.0.into_iter().map(|step| step.result).collect()) } + + /// Calls `eth_getProof` via JSON-RPC returning a [`EIP1186ProofResponse`] + /// returning the account and storage-values of the specified + /// account including the Merkle-proof. + pub async fn get_proof( + &self, + account: Address, + keys: Vec, + block_num: BlockNumber, + ) -> Result { + let account = serialize(&account); + let keys = serialize(&keys); + let num = block_num.serialize(); + self.0 + .request("eth_getProof", [account, keys, num]) + .await + .map_err(|e| Error::JSONRpcError(e.into())) + } } #[cfg(test)] @@ -199,4 +218,44 @@ mod rpc_tests { ); assert!(!trace_by_hash[0].struct_logs.is_empty()); } + + // The test is ignored as the values used depend on the Geth instance used + // each time you run the tests. And we can't assume that everyone will + // have a Geth client synced with mainnet to have unified "test-vectors". + #[ignore] + #[tokio::test] + async fn test_get_proof() { + let transport = Http::new(Url::parse("http://localhost:8545").unwrap()); + let prov = GethClient::new(transport); + + let address = + Address::from_str("0x7F0d15C7FAae65896648C8273B6d7E43f58Fa842") + .unwrap(); + let keys = vec![Word::from_str("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").unwrap()]; + let proof = prov + .get_proof(address, keys, BlockNumber::Latest) + .await + .unwrap(); + const TARGET_PROOF: &str = r#"{ + "address": "0x7f0d15c7faae65896648c8273b6d7e43f58fa842", + "accountProof": [ + "0xf873a12050fb4d3174ec89ef969c09fd4391602169760fb005ad516f5d172cbffb80e955b84ff84d8089056bc75e2d63100000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" + ], + "balance": "0x0", + "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": "0x0", + "storageHash": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "storageProof": [ + { + "key": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "value": "0x0", + "proof": [] + } + ] + }"#; + assert!( + serde_json::from_str::(TARGET_PROOF).unwrap() + == proof + ); + } }