22//! query a Geth node in order to get a Block, Tx or Trace info.
33
44use crate :: eth_types:: {
5- Address , Block , EIP1186ProofResponse , GethExecTrace , Hash ,
5+ Address , Block , Bytes , EIP1186ProofResponse , GethExecTrace , Hash ,
66 ResultGethExecTraces , Transaction , Word , U64 ,
77} ;
88use crate :: Error ;
99use ethers_providers:: JsonRpcClient ;
10+ use serde:: { Serialize , Serializer } ;
1011
1112/// Serialize a type.
1213///
@@ -22,7 +23,7 @@ pub fn serialize<T: serde::Serialize>(t: &T) -> serde_json::Value {
2223#[ derive( Debug ) ]
2324pub enum BlockNumber {
2425 /// Specific block number
25- Num ( U64 ) ,
26+ Num ( u64 ) ,
2627 /// Earliest block
2728 Earliest ,
2829 /// Latest block
@@ -33,26 +34,27 @@ pub enum BlockNumber {
3334
3435impl From < u64 > for BlockNumber {
3536 fn from ( num : u64 ) -> Self {
36- BlockNumber :: Num ( U64 :: from ( num) )
37+ BlockNumber :: Num ( num)
3738 }
3839}
3940
40- impl BlockNumber {
41- /// Serializes a BlockNumber as a [`Value`](serde_json::Value) to be able to
42- /// throw it into a JSON-RPC request.
43- pub fn serialize ( self ) -> serde_json:: Value {
41+ impl Serialize for BlockNumber {
42+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
43+ where
44+ S : Serializer ,
45+ {
4446 match self {
45- BlockNumber :: Num ( num) => serialize ( & num) ,
46- BlockNumber :: Earliest => serialize ( & "earliest" ) ,
47- BlockNumber :: Latest => serialize ( & "latest" ) ,
48- BlockNumber :: Pending => serialize ( & "pending" ) ,
47+ BlockNumber :: Num ( num) => U64 :: from ( * num) . serialize ( serializer ) ,
48+ BlockNumber :: Earliest => "earliest" . serialize ( serializer ) ,
49+ BlockNumber :: Latest => "latest" . serialize ( serializer ) ,
50+ BlockNumber :: Pending => "pending" . serialize ( serializer ) ,
4951 }
5052 }
5153}
5254
5355/// Placeholder structure designed to contain the methods that the BusMapping
5456/// needs in order to enable Geth queries.
55- pub struct GethClient < P : JsonRpcClient > ( P ) ;
57+ pub struct GethClient < P : JsonRpcClient > ( pub P ) ;
5658
5759impl < P : JsonRpcClient > GethClient < P > {
5860 /// Generates a new `GethClient` instance.
@@ -81,7 +83,7 @@ impl<P: JsonRpcClient> GethClient<P> {
8183 & self ,
8284 block_num : BlockNumber ,
8385 ) -> Result < Block < Transaction > , Error > {
84- let num = block_num . serialize ( ) ;
86+ let num = serialize ( & block_num ) ;
8587 let flag = serialize ( & true ) ;
8688 self . 0
8789 . request ( "eth_getBlockByNumber" , [ num, flag] )
@@ -112,7 +114,7 @@ impl<P: JsonRpcClient> GethClient<P> {
112114 & self ,
113115 block_num : BlockNumber ,
114116 ) -> Result < Vec < GethExecTrace > , Error > {
115- let num = block_num . serialize ( ) ;
117+ let num = serialize ( & block_num ) ;
116118 let resp: ResultGethExecTraces = self
117119 . 0
118120 . request ( "debug_traceBlockByNumber" , [ num] )
@@ -121,9 +123,25 @@ impl<P: JsonRpcClient> GethClient<P> {
121123 Ok ( resp. 0 . into_iter ( ) . map ( |step| step. result ) . collect ( ) )
122124 }
123125
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.
126+ /// Calls `eth_getCode` via JSON-RPC returning a contract code
127+ pub async fn get_code_by_address (
128+ & self ,
129+ contract_address : Address ,
130+ block_num : BlockNumber ,
131+ ) -> Result < Vec < u8 > , Error > {
132+ let address = serialize ( & contract_address) ;
133+ let num = serialize ( & block_num) ;
134+ let resp: Bytes = self
135+ . 0
136+ . request ( "eth_getCode" , [ address, num] )
137+ . await
138+ . map_err ( |e| Error :: JSONRpcError ( e. into ( ) ) ) ?;
139+ Ok ( resp. to_vec ( ) )
140+ }
141+
142+ /// Calls `eth_getProof` via JSON-RPC returning a
143+ /// [`EIP1186ProofResponse`] returning the account and
144+ /// storage-values of the specified account including the Merkle-proof.
127145 pub async fn get_proof (
128146 & self ,
129147 account : Address ,
@@ -132,130 +150,12 @@ impl<P: JsonRpcClient> GethClient<P> {
132150 ) -> Result < EIP1186ProofResponse , Error > {
133151 let account = serialize ( & account) ;
134152 let keys = serialize ( & keys) ;
135- let num = block_num . serialize ( ) ;
153+ let num = serialize ( & block_num ) ;
136154 self . 0
137155 . request ( "eth_getProof" , [ account, keys, num] )
138156 . await
139157 . map_err ( |e| Error :: JSONRpcError ( e. into ( ) ) )
140158 }
141159}
142160
143- #[ cfg( test) ]
144- mod rpc_tests {
145- use super :: * ;
146- use ethers_providers:: Http ;
147- use std:: str:: FromStr ;
148- use url:: Url ;
149-
150- // The test is ignored as the values used depend on the Geth instance used
151- // each time you run the tests. And we can't assume that everyone will
152- // have a Geth client synced with mainnet to have unified "test-vectors".
153- #[ ignore]
154- #[ tokio:: test]
155- async fn test_get_block_by_hash ( ) {
156- let transport = Http :: new ( Url :: parse ( "http://localhost:8545" ) . unwrap ( ) ) ;
157-
158- let hash = Hash :: from_str ( "0xe4f7aa19a76fcf31a6adff3b400300849e39dd84076765fb3af09d05ee9d787a" ) . unwrap ( ) ;
159- let prov = GethClient :: new ( transport) ;
160- let block_by_hash = prov. get_block_by_hash ( hash) . await . unwrap ( ) ;
161- assert ! ( hash == block_by_hash. hash. unwrap( ) ) ;
162- }
163-
164- // The test is ignored as the values used depend on the Geth instance used
165- // each time you run the tests. And we can't assume that everyone will
166- // have a Geth client synced with mainnet to have unified "test-vectors".
167- #[ ignore]
168- #[ tokio:: test]
169- async fn test_get_block_by_number ( ) {
170- let transport = Http :: new ( Url :: parse ( "http://localhost:8545" ) . unwrap ( ) ) ;
171-
172- let hash = Hash :: from_str ( "0xe4f7aa19a76fcf31a6adff3b400300849e39dd84076765fb3af09d05ee9d787a" ) . unwrap ( ) ;
173- let prov = GethClient :: new ( transport) ;
174- let block_by_num_latest =
175- prov. get_block_by_number ( BlockNumber :: Latest ) . await . unwrap ( ) ;
176- assert ! ( hash == block_by_num_latest. hash. unwrap( ) ) ;
177- let block_by_num = prov. get_block_by_number ( 1u64 . into ( ) ) . await . unwrap ( ) ;
178- assert ! (
179- block_by_num. transactions[ 0 ] . hash
180- == block_by_num_latest. transactions[ 0 ] . hash
181- ) ;
182- }
183-
184- // The test is ignored as the values used depend on the Geth instance used
185- // each time you run the tests. And we can't assume that everyone will
186- // have a Geth client synced with mainnet to have unified "test-vectors".
187- #[ ignore]
188- #[ tokio:: test]
189- async fn test_trace_block_by_hash ( ) {
190- let transport = Http :: new ( Url :: parse ( "http://localhost:8545" ) . unwrap ( ) ) ;
191-
192- let hash = Hash :: from_str ( "0xe2d191e9f663a3a950519eadeadbd614965b694a65a318a0b8f053f2d14261ff" ) . unwrap ( ) ;
193- let prov = GethClient :: new ( transport) ;
194- let trace_by_hash = prov. trace_block_by_hash ( hash) . await . unwrap ( ) ;
195- // Since we called in the test block the same transaction twice the len
196- // should be the same and != 0.
197- assert ! (
198- trace_by_hash[ 0 ] . struct_logs. len( )
199- == trace_by_hash[ 1 ] . struct_logs. len( )
200- ) ;
201- assert ! ( !trace_by_hash[ 0 ] . struct_logs. is_empty( ) ) ;
202- }
203-
204- // The test is ignored as the values used depend on the Geth instance used
205- // each time you run the tests. And we can't assume that everyone will
206- // have a Geth client synced with mainnet to have unified "test-vectors".
207- #[ ignore]
208- #[ tokio:: test]
209- async fn test_trace_block_by_number ( ) {
210- let transport = Http :: new ( Url :: parse ( "http://localhost:8545" ) . unwrap ( ) ) ;
211- let prov = GethClient :: new ( transport) ;
212- let trace_by_hash = prov. trace_block_by_number ( 5 . into ( ) ) . await . unwrap ( ) ;
213- // Since we called in the test block the same transaction twice the len
214- // should be the same and != 0.
215- assert ! (
216- trace_by_hash[ 0 ] . struct_logs. len( )
217- == trace_by_hash[ 1 ] . struct_logs. len( )
218- ) ;
219- assert ! ( !trace_by_hash[ 0 ] . struct_logs. is_empty( ) ) ;
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- }
261- }
161+ // Integration tests found in `integration-tests/tests/rpc.rs`.
0 commit comments