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
- Address , Block , EIP1186ProofResponse , GethExecTrace , Hash ,
5
+ Address , Block , Bytes , EIP1186ProofResponse , GethExecTrace , Hash ,
6
6
ResultGethExecTraces , Transaction , Word , U64 ,
7
7
} ;
8
8
use crate :: Error ;
9
9
use ethers_providers:: JsonRpcClient ;
10
+ use serde:: { Serialize , Serializer } ;
10
11
11
12
/// Serialize a type.
12
13
///
@@ -22,7 +23,7 @@ pub fn serialize<T: serde::Serialize>(t: &T) -> serde_json::Value {
22
23
#[ derive( Debug ) ]
23
24
pub enum BlockNumber {
24
25
/// Specific block number
25
- Num ( U64 ) ,
26
+ Num ( u64 ) ,
26
27
/// Earliest block
27
28
Earliest ,
28
29
/// Latest block
@@ -33,26 +34,27 @@ pub enum BlockNumber {
33
34
34
35
impl From < u64 > for BlockNumber {
35
36
fn from ( num : u64 ) -> Self {
36
- BlockNumber :: Num ( U64 :: from ( num) )
37
+ BlockNumber :: Num ( num)
37
38
}
38
39
}
39
40
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
+ {
44
46
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 ) ,
49
51
}
50
52
}
51
53
}
52
54
53
55
/// Placeholder structure designed to contain the methods that the BusMapping
54
56
/// needs in order to enable Geth queries.
55
- pub struct GethClient < P : JsonRpcClient > ( P ) ;
57
+ pub struct GethClient < P : JsonRpcClient > ( pub P ) ;
56
58
57
59
impl < P : JsonRpcClient > GethClient < P > {
58
60
/// Generates a new `GethClient` instance.
@@ -81,7 +83,7 @@ impl<P: JsonRpcClient> GethClient<P> {
81
83
& self ,
82
84
block_num : BlockNumber ,
83
85
) -> Result < Block < Transaction > , Error > {
84
- let num = block_num . serialize ( ) ;
86
+ let num = serialize ( & block_num ) ;
85
87
let flag = serialize ( & true ) ;
86
88
self . 0
87
89
. request ( "eth_getBlockByNumber" , [ num, flag] )
@@ -112,7 +114,7 @@ impl<P: JsonRpcClient> GethClient<P> {
112
114
& self ,
113
115
block_num : BlockNumber ,
114
116
) -> Result < Vec < GethExecTrace > , Error > {
115
- let num = block_num . serialize ( ) ;
117
+ let num = serialize ( & block_num ) ;
116
118
let resp: ResultGethExecTraces = self
117
119
. 0
118
120
. request ( "debug_traceBlockByNumber" , [ num] )
@@ -121,9 +123,25 @@ impl<P: JsonRpcClient> GethClient<P> {
121
123
Ok ( resp. 0 . into_iter ( ) . map ( |step| step. result ) . collect ( ) )
122
124
}
123
125
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.
127
145
pub async fn get_proof (
128
146
& self ,
129
147
account : Address ,
@@ -132,130 +150,12 @@ impl<P: JsonRpcClient> GethClient<P> {
132
150
) -> Result < EIP1186ProofResponse , Error > {
133
151
let account = serialize ( & account) ;
134
152
let keys = serialize ( & keys) ;
135
- let num = block_num . serialize ( ) ;
153
+ let num = serialize ( & block_num ) ;
136
154
self . 0
137
155
. request ( "eth_getProof" , [ account, keys, num] )
138
156
. await
139
157
. map_err ( |e| Error :: JSONRpcError ( e. into ( ) ) )
140
158
}
141
159
}
142
160
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