mwc_web3/api/
eth.rs

1//! `Eth` namespace
2
3use crate::{
4    api::Namespace,
5    helpers::{self, CallFuture},
6    types::{
7        Address, Block, BlockHeader, BlockId, BlockNumber, Bytes, CallRequest, Filter, Index, Log, SyncState,
8        Transaction, TransactionId, TransactionReceipt, TransactionRequest, Work, H256, H520, H64, U256, U64,
9    },
10    Transport,
11};
12
13/// `Eth` namespace
14#[derive(Debug, Clone)]
15pub struct Eth<T> {
16    transport: T,
17}
18
19impl<T: Transport> Namespace<T> for Eth<T> {
20    fn new(transport: T) -> Self
21    where
22        Self: Sized,
23    {
24        Eth { transport }
25    }
26
27    fn transport(&self) -> &T {
28        &self.transport
29    }
30}
31
32impl<T: Transport> Eth<T> {
33    /// Get list of available accounts.
34    pub fn accounts(&self) -> CallFuture<Vec<Address>, T::Out> {
35        CallFuture::new(self.transport.execute("eth_accounts", vec![]))
36    }
37
38    /// Get current block number
39    pub fn block_number(&self) -> CallFuture<U64, T::Out> {
40        CallFuture::new(self.transport.execute("eth_blockNumber", vec![]))
41    }
42
43    /// Call a constant method of contract without changing the state of the blockchain.
44    pub fn call(&self, req: CallRequest, block: Option<BlockId>) -> CallFuture<Bytes, T::Out> {
45        let req = helpers::serialize(&req);
46        let block = helpers::serialize(&block.unwrap_or_else(|| BlockNumber::Latest.into()));
47
48        CallFuture::new(self.transport.execute("eth_call", vec![req, block]))
49    }
50
51    /// Get coinbase address
52    pub fn coinbase(&self) -> CallFuture<Address, T::Out> {
53        CallFuture::new(self.transport.execute("eth_coinbase", vec![]))
54    }
55
56    /// Compile LLL
57    pub fn compile_lll(&self, code: String) -> CallFuture<Bytes, T::Out> {
58        let code = helpers::serialize(&code);
59        CallFuture::new(self.transport.execute("eth_compileLLL", vec![code]))
60    }
61
62    /// Compile Solidity
63    pub fn compile_solidity(&self, code: String) -> CallFuture<Bytes, T::Out> {
64        let code = helpers::serialize(&code);
65        CallFuture::new(self.transport.execute("eth_compileSolidity", vec![code]))
66    }
67
68    /// Compile Serpent
69    pub fn compile_serpent(&self, code: String) -> CallFuture<Bytes, T::Out> {
70        let code = helpers::serialize(&code);
71        CallFuture::new(self.transport.execute("eth_compileSerpent", vec![code]))
72    }
73
74    /// Call a contract without changing the state of the blockchain to estimate gas usage.
75    pub fn estimate_gas(&self, req: CallRequest, block: Option<BlockNumber>) -> CallFuture<U256, T::Out> {
76        let req = helpers::serialize(&req);
77
78        let args = match block {
79            Some(block) => vec![req, helpers::serialize(&block)],
80            None => vec![req],
81        };
82
83        CallFuture::new(self.transport.execute("eth_estimateGas", args))
84    }
85
86    /// Get current recommended gas price
87    pub fn gas_price(&self) -> CallFuture<U256, T::Out> {
88        CallFuture::new(self.transport.execute("eth_gasPrice", vec![]))
89    }
90
91    /// Get balance of given address
92    pub fn balance(&self, address: Address, block: Option<BlockNumber>) -> CallFuture<U256, T::Out> {
93        let address = helpers::serialize(&address);
94        let block = helpers::serialize(&block.unwrap_or(BlockNumber::Latest));
95
96        CallFuture::new(self.transport.execute("eth_getBalance", vec![address, block]))
97    }
98
99    /// Get all logs matching a given filter object
100    pub fn logs(&self, filter: Filter) -> CallFuture<Vec<Log>, T::Out> {
101        let filter = helpers::serialize(&filter);
102        CallFuture::new(self.transport.execute("eth_getLogs", vec![filter]))
103    }
104
105    /// Get block details with transaction hashes.
106    pub fn block(&self, block: BlockId) -> CallFuture<Option<Block<H256>>, T::Out> {
107        let include_txs = helpers::serialize(&false);
108
109        let result = match block {
110            BlockId::Hash(hash) => {
111                let hash = helpers::serialize(&hash);
112                self.transport.execute("eth_getBlockByHash", vec![hash, include_txs])
113            }
114            BlockId::Number(num) => {
115                let num = helpers::serialize(&num);
116                self.transport.execute("eth_getBlockByNumber", vec![num, include_txs])
117            }
118        };
119
120        CallFuture::new(result)
121    }
122
123    /// Get block details with full transaction objects.
124    pub fn block_with_txs(&self, block: BlockId) -> CallFuture<Option<Block<Transaction>>, T::Out> {
125        let include_txs = helpers::serialize(&true);
126
127        let result = match block {
128            BlockId::Hash(hash) => {
129                let hash = helpers::serialize(&hash);
130                self.transport.execute("eth_getBlockByHash", vec![hash, include_txs])
131            }
132            BlockId::Number(num) => {
133                let num = helpers::serialize(&num);
134                self.transport.execute("eth_getBlockByNumber", vec![num, include_txs])
135            }
136        };
137
138        CallFuture::new(result)
139    }
140
141    /// Get number of transactions in block
142    pub fn block_transaction_count(&self, block: BlockId) -> CallFuture<Option<U256>, T::Out> {
143        let result = match block {
144            BlockId::Hash(hash) => {
145                let hash = helpers::serialize(&hash);
146                self.transport.execute("eth_getBlockTransactionCountByHash", vec![hash])
147            }
148            BlockId::Number(num) => {
149                let num = helpers::serialize(&num);
150                self.transport
151                    .execute("eth_getBlockTransactionCountByNumber", vec![num])
152            }
153        };
154
155        CallFuture::new(result)
156    }
157
158    /// Get code under given address
159    pub fn code(&self, address: Address, block: Option<BlockNumber>) -> CallFuture<Bytes, T::Out> {
160        let address = helpers::serialize(&address);
161        let block = helpers::serialize(&block.unwrap_or(BlockNumber::Latest));
162
163        CallFuture::new(self.transport.execute("eth_getCode", vec![address, block]))
164    }
165
166    /// Get supported compilers
167    pub fn compilers(&self) -> CallFuture<Vec<String>, T::Out> {
168        CallFuture::new(self.transport.execute("eth_getCompilers", vec![]))
169    }
170
171    /// Get chain id
172    pub fn chain_id(&self) -> CallFuture<U256, T::Out> {
173        CallFuture::new(self.transport.execute("eth_chainId", vec![]))
174    }
175
176    /// Get available user accounts. This method is only available in the browser. With MetaMask,
177    /// this will cause the popup that prompts the user to allow or deny access to their accounts
178    /// to your app.
179    pub fn request_accounts(&self) -> CallFuture<Vec<Address>, T::Out> {
180        CallFuture::new(self.transport.execute("eth_requestAccounts", vec![]))
181    }
182
183    /// Get storage entry
184    pub fn storage(&self, address: Address, idx: U256, block: Option<BlockNumber>) -> CallFuture<H256, T::Out> {
185        let address = helpers::serialize(&address);
186        let idx = helpers::serialize(&idx);
187        let block = helpers::serialize(&block.unwrap_or(BlockNumber::Latest));
188
189        CallFuture::new(self.transport.execute("eth_getStorageAt", vec![address, idx, block]))
190    }
191
192    /// Get nonce
193    pub fn transaction_count(&self, address: Address, block: Option<BlockNumber>) -> CallFuture<U256, T::Out> {
194        let address = helpers::serialize(&address);
195        let block = helpers::serialize(&block.unwrap_or(BlockNumber::Latest));
196
197        CallFuture::new(self.transport.execute("eth_getTransactionCount", vec![address, block]))
198    }
199
200    /// Get transaction
201    pub fn transaction(&self, id: TransactionId) -> CallFuture<Option<Transaction>, T::Out> {
202        let result = match id {
203            TransactionId::Hash(hash) => {
204                let hash = helpers::serialize(&hash);
205                self.transport.execute("eth_getTransactionByHash", vec![hash])
206            }
207            TransactionId::Block(BlockId::Hash(hash), index) => {
208                let hash = helpers::serialize(&hash);
209                let idx = helpers::serialize(&index);
210                self.transport
211                    .execute("eth_getTransactionByBlockHashAndIndex", vec![hash, idx])
212            }
213            TransactionId::Block(BlockId::Number(number), index) => {
214                let number = helpers::serialize(&number);
215                let idx = helpers::serialize(&index);
216                self.transport
217                    .execute("eth_getTransactionByBlockNumberAndIndex", vec![number, idx])
218            }
219        };
220
221        CallFuture::new(result)
222    }
223
224    /// Get transaction receipt
225    pub fn transaction_receipt(&self, hash: H256) -> CallFuture<Option<TransactionReceipt>, T::Out> {
226        let hash = helpers::serialize(&hash);
227
228        CallFuture::new(self.transport.execute("eth_getTransactionReceipt", vec![hash]))
229    }
230
231    /// Get uncle header by block ID and uncle index.
232    ///
233    /// This method is meant for TurboGeth compatiblity,
234    /// which is missing transaction hashes in the response.
235    pub fn uncle_header(&self, block: BlockId, index: Index) -> CallFuture<Option<BlockHeader>, T::Out> {
236        self.fetch_uncle(block, index)
237    }
238
239    /// Get uncle by block ID and uncle index -- transactions only has hashes.
240    pub fn uncle(&self, block: BlockId, index: Index) -> CallFuture<Option<Block<H256>>, T::Out> {
241        self.fetch_uncle(block, index)
242    }
243
244    fn fetch_uncle<X>(&self, block: BlockId, index: Index) -> CallFuture<Option<X>, T::Out> {
245        let index = helpers::serialize(&index);
246
247        let result = match block {
248            BlockId::Hash(hash) => {
249                let hash = helpers::serialize(&hash);
250                self.transport
251                    .execute("eth_getUncleByBlockHashAndIndex", vec![hash, index])
252            }
253            BlockId::Number(num) => {
254                let num = helpers::serialize(&num);
255                self.transport
256                    .execute("eth_getUncleByBlockNumberAndIndex", vec![num, index])
257            }
258        };
259
260        CallFuture::new(result)
261    }
262
263    /// Get uncle count in block
264    pub fn uncle_count(&self, block: BlockId) -> CallFuture<Option<U256>, T::Out> {
265        let result = match block {
266            BlockId::Hash(hash) => {
267                let hash = helpers::serialize(&hash);
268                self.transport.execute("eth_getUncleCountByBlockHash", vec![hash])
269            }
270            BlockId::Number(num) => {
271                let num = helpers::serialize(&num);
272                self.transport.execute("eth_getUncleCountByBlockNumber", vec![num])
273            }
274        };
275
276        CallFuture::new(result)
277    }
278
279    /// Get work package
280    pub fn work(&self) -> CallFuture<Work, T::Out> {
281        CallFuture::new(self.transport.execute("eth_getWork", vec![]))
282    }
283
284    /// Get hash rate
285    pub fn hashrate(&self) -> CallFuture<U256, T::Out> {
286        CallFuture::new(self.transport.execute("eth_hashrate", vec![]))
287    }
288
289    /// Get mining status
290    pub fn mining(&self) -> CallFuture<bool, T::Out> {
291        CallFuture::new(self.transport.execute("eth_mining", vec![]))
292    }
293
294    /// Start new block filter
295    pub fn new_block_filter(&self) -> CallFuture<U256, T::Out> {
296        CallFuture::new(self.transport.execute("eth_newBlockFilter", vec![]))
297    }
298
299    /// Start new pending transaction filter
300    pub fn new_pending_transaction_filter(&self) -> CallFuture<U256, T::Out> {
301        CallFuture::new(self.transport.execute("eth_newPendingTransactionFilter", vec![]))
302    }
303
304    /// Start new pending transaction filter
305    pub fn protocol_version(&self) -> CallFuture<String, T::Out> {
306        CallFuture::new(self.transport.execute("eth_protocolVersion", vec![]))
307    }
308
309    /// Sends a rlp-encoded signed transaction
310    pub fn send_raw_transaction(&self, rlp: Bytes) -> CallFuture<H256, T::Out> {
311        let rlp = helpers::serialize(&rlp);
312        CallFuture::new(self.transport.execute("eth_sendRawTransaction", vec![rlp]))
313    }
314
315    /// Sends a transaction transaction
316    pub fn send_transaction(&self, tx: TransactionRequest) -> CallFuture<H256, T::Out> {
317        let tx = helpers::serialize(&tx);
318        CallFuture::new(self.transport.execute("eth_sendTransaction", vec![tx]))
319    }
320
321    /// Signs a hash of given data
322    pub fn sign(&self, address: Address, data: Bytes) -> CallFuture<H520, T::Out> {
323        let address = helpers::serialize(&address);
324        let data = helpers::serialize(&data);
325        CallFuture::new(self.transport.execute("eth_sign", vec![address, data]))
326    }
327
328    /// Submit hashrate of external miner
329    pub fn submit_hashrate(&self, rate: U256, id: H256) -> CallFuture<bool, T::Out> {
330        let rate = helpers::serialize(&rate);
331        let id = helpers::serialize(&id);
332        CallFuture::new(self.transport.execute("eth_submitHashrate", vec![rate, id]))
333    }
334
335    /// Submit work of external miner
336    pub fn submit_work(&self, nonce: H64, pow_hash: H256, mix_hash: H256) -> CallFuture<bool, T::Out> {
337        let nonce = helpers::serialize(&nonce);
338        let pow_hash = helpers::serialize(&pow_hash);
339        let mix_hash = helpers::serialize(&mix_hash);
340        CallFuture::new(
341            self.transport
342                .execute("eth_submitWork", vec![nonce, pow_hash, mix_hash]),
343        )
344    }
345
346    /// Get syncing status
347    pub fn syncing(&self) -> CallFuture<SyncState, T::Out> {
348        CallFuture::new(self.transport.execute("eth_syncing", vec![]))
349    }
350}
351
352#[cfg(test)]
353mod tests {
354    use super::Eth;
355    use crate::{
356        api::Namespace,
357        rpc::Value,
358        types::{
359            Address, Block, BlockHeader, BlockId, BlockNumber, CallRequest, FilterBuilder, Log, SyncInfo, SyncState,
360            Transaction, TransactionId, TransactionReceipt, TransactionRequest, Work, H256, H520, H64,
361        },
362    };
363    use hex_literal::hex;
364    use serde_json::json;
365
366    // taken from RPC docs.
367    const EXAMPLE_BLOCK: &str = r#"{
368    "number": "0x1b4",
369    "hash": "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
370    "parentHash": "0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5",
371    "mixHash": "0x1010101010101010101010101010101010101010101010101010101010101010",
372    "nonce": "0x0000000000000000",
373    "sealFields": [
374      "0xe04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f2",
375      "0x0000000000000042"
376    ],
377    "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
378    "logsBloom":  "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
379    "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
380    "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
381    "stateRoot": "0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff",
382    "miner": "0x4e65fda2159562a496f9f3522f89122a3088497a",
383    "difficulty": "0x27f07",
384    "totalDifficulty": "0x27f07",
385    "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
386    "size": "0x27f07",
387    "gasLimit": "0x9f759",
388    "minGasPrice": "0x9f759",
389    "gasUsed": "0x9f759",
390    "timestamp": "0x54e34e8e",
391    "transactions": [],
392    "uncles": []
393  }"#;
394
395    // response from RPC request {"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["pending", false],"id":1}.
396    const EXAMPLE_PENDING_BLOCK: &str = r#"{
397        "author": "0x0000000000000000000000000000000000000000",
398        "difficulty": "0x7eac2e8c440b2",
399        "extraData": "0xde830207028f5061726974792d457468657265756d86312e34312e30826c69",
400        "gasLimit": "0x974a0a",
401        "gasUsed": "0x44dd8",
402        "hash": null,
403        "logsBloom": null,
404        "miner": "0x0000000000000000000000000000000000000000",
405        "number": null,
406        "parentHash": "0xb4bb0904f19fd05ed527191f21ea27bd4f2d81903f77bfa2626631617001327c",
407        "receiptsRoot": "0x855c8c3b1c985b6bc5fd975a37b764095542b98a177588b887e197fcc5e0a0cd",
408        "sealFields": [],
409        "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
410        "size": "0x8b6",
411        "stateRoot": "0xfa035b07c349fb33768aebeb988639bd2ca7d5284170f29808ead43482a432c5",
412        "timestamp": "0x5ea09b90",
413        "totalDifficulty": "0x332b576efbc4023b848",
414        "transactions": [
415          "0x8e0d2bdfd47d7e68d5c86c30cbe4967ffcf920745a4b8177e1911fafd48e851a",
416          "0x2ac5f94e2d653d64fe89f7af2140600e4b7a59b3345700b5424bd4fae08212af",
417          "0x75d3e2d2ab548f4ca6e9f0c27306cedf28074ce60f39a6e78f56ea3f4a22e2d5",
418          "0xbcdb4f0829c7191a14e03dba0783fb015fa921d06b683e0ce8afb938745f89f7",
419          "0x75cede4d4cdb8402b242a1b1b39a23d537b2fee6a14783eaab67aa1e79bd71cd",
420          "0x50e406de9432a3589681b1eb3093ab6aba0895b5dc755588ca64735386591425",
421          "0x101e8b02d478dfab2266688b53668039107e98feacf085dcf9bfd24f390ec17d",
422          "0x22c75911be879047f4b0480fa07b2c2a77518571fb358d92b47c456d7065a76f",
423          "0x7715b514ba8ead48117b581f9ebcc61696a5b91f9111c55a7087e91474a58ec7",
424          "0x95dd913782cd4bfe5550a8f9102ba821f9a76691780c833d5130e311d62eb638"
425        ],
426        "transactionsRoot": "0x3acac83d7cc227b0c9a9ab1702964e70d7c8d1bfbf0f587b40e2a0aa0048aa44",
427        "uncles": []
428      }"#;
429
430    // taken from RPC docs, but with leading `00` added to `blockHash`
431    // and `transactionHash` fields because RPC docs currently show
432    // 31-byte values in both positions (must be 32 bytes).
433    const EXAMPLE_LOG: &str = r#"{
434    "logIndex": "0x1",
435    "blockNumber":"0x1b4",
436    "blockHash": "0x008216c5785ac562ff41e2dcfdf5785ac562ff41e2dcfdf829c5a142f1fccd7d",
437    "transactionHash":  "0x00df829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf",
438    "transactionIndex": "0x0",
439    "address": "0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d",
440    "data":"0x0000000000000000000000000000000000000000000000000000000000000000",
441    "topics": ["0x59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a5"]
442  }"#;
443
444    // taken from RPC docs.
445    const EXAMPLE_TX: &str = r#"{
446    "hash": "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b",
447    "nonce": "0x0",
448    "blockHash": "0xbeab0aa2411b7ab17f30a99d3cb9c6ef2fc5426d6ad6fd9e2a26a6aed1d1055b",
449    "blockNumber": "0x15df",
450    "transactionIndex": "0x1",
451    "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
452    "to":   "0x85dd43d8a49eeb85d32cf465507dd71d507100c1",
453    "value": "0x7f110",
454    "gas": "0x7f110",
455    "gasPrice": "0x09184e72a000",
456    "input": "0x603880600c6000396000f300603880600c6000396000f3603880600c6000396000f360"
457  }"#;
458
459    // taken from RPC docs.
460    const EXAMPLE_RECEIPT: &str = r#"{
461    "hash": "0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238",
462    "index": "0x1",
463    "transactionHash": "0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238",
464    "transactionIndex": "0x1",
465    "blockNumber": "0xb",
466    "blockHash": "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b",
467    "cumulativeGasUsed": "0x33bc",
468    "gasUsed": "0x4dc",
469    "contractAddress": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
470    "logsBloom":  "0x0e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d15273310e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
471    "logs": []
472  }"#;
473
474    rpc_test! (
475      Eth:accounts => "eth_accounts";
476      Value::Array(vec![Value::String("0x0000000000000000000000000000000000000123".into())]) => vec![Address::from_low_u64_be(0x123)]
477    );
478
479    rpc_test! (
480      Eth:block_number => "eth_blockNumber";
481      Value::String("0x123".into()) => 0x123
482    );
483
484    rpc_test! (
485      Eth:call, CallRequest {
486        from: None, to: Some(Address::from_low_u64_be(0x123)),
487        gas: None, gas_price: None,
488        value: Some(0x1.into()), data: None,
489      }, None
490      =>
491      "eth_call", vec![r#"{"to":"0x0000000000000000000000000000000000000123","value":"0x1"}"#, r#""latest""#];
492      Value::String("0x010203".into()) => hex!("010203")
493    );
494
495    rpc_test! (
496      Eth:coinbase => "eth_coinbase";
497      Value::String("0x0000000000000000000000000000000000000123".into()) => Address::from_low_u64_be(0x123)
498    );
499
500    rpc_test! (
501      Eth:compile_lll, "code" => "eth_compileLLL", vec![r#""code""#];
502      Value::String("0x0123".into()) => hex!("0123")
503    );
504
505    rpc_test! (
506      Eth:compile_solidity, "code" => "eth_compileSolidity", vec![r#""code""#];
507      Value::String("0x0123".into()) => hex!("0123")
508    );
509
510    rpc_test! (
511      Eth:compile_serpent, "code" => "eth_compileSerpent", vec![r#""code""#];
512      Value::String("0x0123".into()) => hex!("0123")
513    );
514
515    rpc_test! (
516      Eth:estimate_gas, CallRequest {
517        from: None, to: Some(Address::from_low_u64_be(0x123)),
518        gas: None, gas_price: None,
519        value: Some(0x1.into()), data: None,
520      }, None
521      =>
522      "eth_estimateGas", vec![r#"{"to":"0x0000000000000000000000000000000000000123","value":"0x1"}"#];
523      Value::String("0x123".into()) => 0x123
524    );
525
526    rpc_test! (
527      Eth:estimate_gas:optional_to_addr, CallRequest {
528        from: None, to: None,
529        gas: None, gas_price: None,
530        value: Some(0x1.into()), data: None,
531      }, None
532      =>
533      "eth_estimateGas", vec![r#"{"value":"0x1"}"#];
534      Value::String("0x5555".into()) => 0x5555
535    );
536
537    rpc_test! (
538      Eth:estimate_gas:for_block, CallRequest {
539        from: None, to: Some(Address::from_low_u64_be(0x123)),
540        gas: None, gas_price: None,
541        value: Some(0x1.into()), data: None,
542      }, Some(0x123.into())
543      =>
544      "eth_estimateGas", vec![r#"{"to":"0x0000000000000000000000000000000000000123","value":"0x1"}"#, r#""0x123""#];
545      Value::String("0x123".into()) => 0x123
546    );
547
548    rpc_test! (
549      Eth:gas_price => "eth_gasPrice";
550      Value::String("0x123".into()) => 0x123
551    );
552
553    rpc_test! (
554      Eth:balance, Address::from_low_u64_be(0x123), None
555      =>
556      "eth_getBalance", vec![r#""0x0000000000000000000000000000000000000123""#, r#""latest""#];
557      Value::String("0x123".into()) => 0x123
558    );
559
560    rpc_test! (
561      Eth:logs, FilterBuilder::default().build() => "eth_getLogs", vec!["{}"];
562      Value::Array(vec![::serde_json::from_str(EXAMPLE_LOG).unwrap()])
563      => vec![::serde_json::from_str::<Log>(EXAMPLE_LOG).unwrap()]
564    );
565
566    rpc_test! (
567      Eth:block:block_by_hash, BlockId::Hash(H256::from_low_u64_be(0x123))
568      =>
569      "eth_getBlockByHash", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#, r#"false"#];
570      ::serde_json::from_str(EXAMPLE_BLOCK).unwrap()
571      => Some(::serde_json::from_str::<Block<H256>>(EXAMPLE_BLOCK).unwrap())
572    );
573
574    rpc_test! (
575      Eth:block, BlockNumber::Pending
576      =>
577      "eth_getBlockByNumber", vec![r#""pending""#, r#"false"#];
578      ::serde_json::from_str(EXAMPLE_PENDING_BLOCK).unwrap()
579      => Some(::serde_json::from_str::<Block<H256>>(EXAMPLE_PENDING_BLOCK).unwrap())
580    );
581
582    rpc_test! (
583      Eth:block_with_txs, BlockNumber::Pending
584      =>
585      "eth_getBlockByNumber", vec![r#""pending""#, r#"true"#];
586      ::serde_json::from_str(EXAMPLE_BLOCK).unwrap()
587      => Some(::serde_json::from_str::<Block<Transaction>>(EXAMPLE_BLOCK).unwrap())
588    );
589
590    rpc_test! (
591      Eth:block_transaction_count:block_tx_count_by_hash, BlockId::Hash(H256::from_low_u64_be(0x123))
592      =>
593      "eth_getBlockTransactionCountByHash", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#];
594      Value::String("0x123".into()) => Some(0x123.into())
595    );
596
597    rpc_test! (
598      Eth:block_transaction_count, BlockNumber::Pending
599      =>
600      "eth_getBlockTransactionCountByNumber", vec![r#""pending""#];
601      Value::Null => None
602    );
603
604    rpc_test! (
605      Eth:code, H256::from_low_u64_be(0x123), Some(BlockNumber::Pending)
606      =>
607      "eth_getCode", vec![r#""0x0000000000000000000000000000000000000123""#, r#""pending""#];
608      Value::String("0x0123".into()) => hex!("0123")
609    );
610
611    rpc_test! (
612      Eth:compilers => "eth_getCompilers";
613      Value::Array(vec![]) => vec![]
614    );
615
616    rpc_test! (
617      Eth:chain_id => "eth_chainId";
618      Value::String("0x123".into()) => 0x123
619    );
620
621    rpc_test! (
622      Eth:storage, Address::from_low_u64_be(0x123), 0x456, None
623      =>
624      "eth_getStorageAt", vec![
625        r#""0x0000000000000000000000000000000000000123""#,
626        r#""0x456""#,
627        r#""latest""#
628      ];
629      Value::String("0x0000000000000000000000000000000000000000000000000000000000000123".into()) => H256::from_low_u64_be(0x123)
630    );
631
632    rpc_test! (
633      Eth:transaction_count, Address::from_low_u64_be(0x123), None
634      =>
635      "eth_getTransactionCount", vec![r#""0x0000000000000000000000000000000000000123""#, r#""latest""#];
636      Value::String("0x123".into()) => 0x123
637    );
638
639    rpc_test! (
640      Eth:transaction:tx_by_hash, TransactionId::Hash(H256::from_low_u64_be(0x123))
641      =>
642      "eth_getTransactionByHash", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#];
643      ::serde_json::from_str(EXAMPLE_TX).unwrap()
644      => Some(::serde_json::from_str::<Transaction>(EXAMPLE_TX).unwrap())
645    );
646
647    rpc_test! (
648      Eth:transaction:tx_by_block_hash_and_index, TransactionId::Block(
649        BlockId::Hash(H256::from_low_u64_be(0x123)),
650        5.into()
651      )
652      =>
653      "eth_getTransactionByBlockHashAndIndex", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#, r#""0x5""#];
654      Value::Null => None
655    );
656
657    rpc_test! (
658      Eth:transaction:tx_by_block_no_and_index, TransactionId::Block(
659        BlockNumber::Pending.into(),
660        5.into()
661      )
662      =>
663      "eth_getTransactionByBlockNumberAndIndex", vec![r#""pending""#, r#""0x5""#];
664      ::serde_json::from_str(EXAMPLE_TX).unwrap()
665      => Some(::serde_json::from_str::<Transaction>(EXAMPLE_TX).unwrap())
666    );
667
668    rpc_test! (
669      Eth:transaction_receipt, H256::from_low_u64_be(0x123)
670      =>
671      "eth_getTransactionReceipt", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#];
672      ::serde_json::from_str(EXAMPLE_RECEIPT).unwrap()
673      => Some(::serde_json::from_str::<TransactionReceipt>(EXAMPLE_RECEIPT).unwrap())
674    );
675
676    rpc_test! (
677      Eth:uncle:uncle_by_hash, BlockId::Hash(H256::from_low_u64_be(0x123)), 5
678      =>
679      "eth_getUncleByBlockHashAndIndex", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#, r#""0x5""#];
680      ::serde_json::from_str(EXAMPLE_BLOCK).unwrap()
681      => Some(::serde_json::from_str::<Block<H256>>(EXAMPLE_BLOCK).unwrap())
682    );
683
684    rpc_test! (
685      Eth:uncle_header:uncle_header_by_hash, BlockId::Hash(H256::from_low_u64_be(0x123)), 5
686      =>
687      "eth_getUncleByBlockHashAndIndex", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#, r#""0x5""#];
688      ::serde_json::from_str(EXAMPLE_BLOCK).unwrap()
689      => Some(::serde_json::from_str::<BlockHeader>(EXAMPLE_BLOCK).unwrap())
690    );
691
692    rpc_test! (
693      Eth:uncle:uncle_by_no, BlockNumber::Earliest, 5
694      =>
695      "eth_getUncleByBlockNumberAndIndex", vec![r#""earliest""#, r#""0x5""#];
696      Value::Null => None
697    );
698
699    rpc_test! (
700      Eth:uncle_count:uncle_count_by_hash, BlockId::Hash(H256::from_low_u64_be(0x123))
701      =>
702      "eth_getUncleCountByBlockHash", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#];
703      Value::String("0x123".into())=> Some(0x123.into())
704    );
705
706    rpc_test! (
707      Eth:uncle_count:uncle_count_by_no, BlockNumber::Earliest
708      =>
709      "eth_getUncleCountByBlockNumber", vec![r#""earliest""#];
710      Value::Null => None
711    );
712
713    rpc_test! (
714      Eth:work:work_3 => "eth_getWork";
715      Value::Array(vec![
716        Value::String("0x0000000000000000000000000000000000000000000000000000000000000123".into()),
717        Value::String("0x0000000000000000000000000000000000000000000000000000000000000456".into()),
718        Value::String("0x0000000000000000000000000000000000000000000000000000000000000789".into()),
719      ]) => Work {
720        pow_hash: H256::from_low_u64_be(0x123),
721        seed_hash: H256::from_low_u64_be(0x456),
722        target: H256::from_low_u64_be(0x789),
723        number: None,
724      }
725    );
726
727    rpc_test! (
728      Eth:work:work_4 => "eth_getWork";
729      Value::Array(vec![
730        Value::String("0x0000000000000000000000000000000000000000000000000000000000000123".into()),
731        Value::String("0x0000000000000000000000000000000000000000000000000000000000000456".into()),
732        Value::String("0x0000000000000000000000000000000000000000000000000000000000000789".into()),
733        Value::Number(5.into()),
734      ]) => Work {
735        pow_hash: H256::from_low_u64_be(0x123),
736        seed_hash: H256::from_low_u64_be(0x456),
737        target: H256::from_low_u64_be(0x789),
738        number: Some(5),
739      }
740    );
741
742    rpc_test! (
743      Eth:hashrate => "eth_hashrate";
744      Value::String("0x123".into()) => 0x123
745    );
746
747    rpc_test! (
748      Eth:mining => "eth_mining";
749      Value::Bool(true) => true
750    );
751
752    rpc_test! (
753      Eth:new_block_filter => "eth_newBlockFilter";
754      Value::String("0x123".into()) => 0x123
755    );
756    rpc_test! (
757      Eth:new_pending_transaction_filter => "eth_newPendingTransactionFilter";
758      Value::String("0x123".into()) => 0x123
759    );
760
761    rpc_test! (
762      Eth:protocol_version => "eth_protocolVersion";
763      Value::String("0x123".into()) => "0x123"
764    );
765
766    rpc_test! (
767      Eth:send_raw_transaction, hex!("01020304")
768      =>
769      "eth_sendRawTransaction", vec![r#""0x01020304""#];
770      Value::String("0x0000000000000000000000000000000000000000000000000000000000000123".into()) => H256::from_low_u64_be(0x123)
771    );
772
773    rpc_test! (
774      Eth:send_transaction, TransactionRequest {
775        from: Address::from_low_u64_be(0x123), to: Some(Address::from_low_u64_be(0x123)),
776        gas: None, gas_price: Some(0x1.into()),
777        value: Some(0x1.into()), data: None,
778        nonce: None, condition: None,
779      }
780      =>
781      "eth_sendTransaction", vec![r#"{"from":"0x0000000000000000000000000000000000000123","gasPrice":"0x1","to":"0x0000000000000000000000000000000000000123","value":"0x1"}"#];
782      Value::String("0x0000000000000000000000000000000000000000000000000000000000000123".into()) => H256::from_low_u64_be(0x123)
783    );
784
785    rpc_test! (
786      Eth:sign, H256::from_low_u64_be(0x123), hex!("01020304")
787      =>
788      "eth_sign", vec![r#""0x0000000000000000000000000000000000000123""#, r#""0x01020304""#];
789      Value::String("0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123".into()) => H520::from_low_u64_be(0x123)
790    );
791
792    rpc_test! (
793      Eth:submit_hashrate, 0x123, H256::from_low_u64_be(0x456)
794      =>
795      "eth_submitHashrate", vec![r#""0x123""#, r#""0x0000000000000000000000000000000000000000000000000000000000000456""#];
796      Value::Bool(true) => true
797    );
798
799    rpc_test! (
800      Eth:submit_work, H64::from_low_u64_be(0x123), H256::from_low_u64_be(0x456), H256::from_low_u64_be(0x789)
801      =>
802      "eth_submitWork", vec![r#""0x0000000000000123""#, r#""0x0000000000000000000000000000000000000000000000000000000000000456""#, r#""0x0000000000000000000000000000000000000000000000000000000000000789""#];
803      Value::Bool(true) => true
804    );
805
806    rpc_test! (
807      Eth:syncing:syncing => "eth_syncing";
808      json!({"startingBlock": "0x384","currentBlock": "0x386","highestBlock": "0x454"}) => SyncState::Syncing(SyncInfo { starting_block: 0x384.into(), current_block: 0x386.into(), highest_block: 0x454.into()})
809    );
810
811    rpc_test! {
812      Eth:syncing:not_syncing => "eth_syncing";
813      Value::Bool(false) => SyncState::NotSyncing
814    }
815}