|
2 | 2 | //! query a Geth node in order to get a Block, Tx or Trace info. |
3 | 3 |
|
4 | 4 | use crate::eth_types::{ |
5 | | - Block, GethExecTrace, Hash, ResultGethExecTraces, Transaction, U64, |
| 5 | + Address, Block, EIP1186ProofResponse, GethExecTrace, Hash, |
| 6 | + ResultGethExecTraces, Transaction, Word, U64, |
6 | 7 | }; |
7 | 8 | use crate::Error; |
8 | 9 | use ethers_providers::JsonRpcClient; |
@@ -119,6 +120,24 @@ impl<P: JsonRpcClient> GethClient<P> { |
119 | 120 | .map_err(|e| Error::JSONRpcError(e.into()))?; |
120 | 121 | Ok(resp.0.into_iter().map(|step| step.result).collect()) |
121 | 122 | } |
| 123 | + |
| 124 | + /// Calls `eth_getProof` via JSON-RPC returning a [`EIP1186ProofResponse`] |
| 125 | + /// returning the account and storage-values of the specified |
| 126 | + /// account including the Merkle-proof. |
| 127 | + pub async fn get_proof( |
| 128 | + &self, |
| 129 | + account: Address, |
| 130 | + keys: Vec<Word>, |
| 131 | + block_num: BlockNumber, |
| 132 | + ) -> Result<EIP1186ProofResponse, Error> { |
| 133 | + let account = serialize(&account); |
| 134 | + let keys = serialize(&keys); |
| 135 | + let num = block_num.serialize(); |
| 136 | + self.0 |
| 137 | + .request("eth_getProof", [account, keys, num]) |
| 138 | + .await |
| 139 | + .map_err(|e| Error::JSONRpcError(e.into())) |
| 140 | + } |
122 | 141 | } |
123 | 142 |
|
124 | 143 | #[cfg(test)] |
@@ -199,4 +218,44 @@ mod rpc_tests { |
199 | 218 | ); |
200 | 219 | assert!(!trace_by_hash[0].struct_logs.is_empty()); |
201 | 220 | } |
| 221 | + |
| 222 | + // The test is ignored as the values used depend on the Geth instance used |
| 223 | + // each time you run the tests. And we can't assume that everyone will |
| 224 | + // have a Geth client synced with mainnet to have unified "test-vectors". |
| 225 | + #[ignore] |
| 226 | + #[tokio::test] |
| 227 | + async fn test_get_proof() { |
| 228 | + let transport = Http::new(Url::parse("http://localhost:8545").unwrap()); |
| 229 | + let prov = GethClient::new(transport); |
| 230 | + |
| 231 | + let address = |
| 232 | + Address::from_str("0x7F0d15C7FAae65896648C8273B6d7E43f58Fa842") |
| 233 | + .unwrap(); |
| 234 | + let keys = vec![Word::from_str("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").unwrap()]; |
| 235 | + let proof = prov |
| 236 | + .get_proof(address, keys, BlockNumber::Latest) |
| 237 | + .await |
| 238 | + .unwrap(); |
| 239 | + const TARGET_PROOF: &str = r#"{ |
| 240 | + "address": "0x7f0d15c7faae65896648c8273b6d7e43f58fa842", |
| 241 | + "accountProof": [ |
| 242 | + "0xf873a12050fb4d3174ec89ef969c09fd4391602169760fb005ad516f5d172cbffb80e955b84ff84d8089056bc75e2d63100000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" |
| 243 | + ], |
| 244 | + "balance": "0x0", |
| 245 | + "codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", |
| 246 | + "nonce": "0x0", |
| 247 | + "storageHash": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", |
| 248 | + "storageProof": [ |
| 249 | + { |
| 250 | + "key": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", |
| 251 | + "value": "0x0", |
| 252 | + "proof": [] |
| 253 | + } |
| 254 | + ] |
| 255 | + }"#; |
| 256 | + assert!( |
| 257 | + serde_json::from_str::<EIP1186ProofResponse>(TARGET_PROOF).unwrap() |
| 258 | + == proof |
| 259 | + ); |
| 260 | + } |
202 | 261 | } |
0 commit comments