Skip to main content

eth_jsonrpc_lib/rpc_complete/
complete.rs

1// Copyright Rivtower Technologies LLC.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::rpc_request::{
16    eth_accountsParams, eth_blockNumberParams, eth_callParams, eth_chainIdParams,
17    eth_estimateGasParams, eth_gasPriceParams, eth_getBalanceParams, eth_getBlockByHashParams,
18    eth_getBlockByNumberParams, eth_getBlockTransactionCountByHashParams,
19    eth_getBlockTransactionCountByNumberParams, eth_getCodeParams, eth_getLogsParams,
20    eth_getStorageAtParams, eth_getTransactionByBlockHashAndIndexParams,
21    eth_getTransactionByBlockNumberAndIndexParams, eth_getTransactionByHashParams,
22    eth_getTransactionCountParams, eth_getTransactionReceiptParams, eth_maxPriorityFeePerGasParams,
23    eth_sendRawTransactionParams, eth_sendTransactionParams, eth_syncingParams, net_versionParams,
24    BlockNumberParams, CallParams, EstimateQuotaParams, GetAbiParams, GetBalanceParams,
25    GetBlockByHashParams, GetBlockByNumberParams, GetBlockHeaderParams, GetCensoredAddrsParams,
26    GetCodeParams, GetFilterChangesParams, GetFilterLogsParams, GetLogsParams, GetMetaDataParams,
27    GetPoolTxNumParams, GetStateProofParams, GetStorageKeyParams, GetTransactionCountParams,
28    GetTransactionParams, GetTransactionProofParams, GetTransactionReceiptParams, GetVersionParams,
29    LicenseInfoParams, NewBlockFilterParams, NewFilterParams, OpCensoredAddressParams,
30    PeerCountParams, PeersInfoParams, SendRawTransactionParams, SendTransactionParams,
31    UninstallFilterParams,
32};
33use crate::rpc_request::{Call, JsonRpcRequest, PartialCall, PartialRequest, Request};
34use crate::{impl_for_each_jsonrpc_requests, rpc_types::Params as PartialParams, Error};
35use serde_json;
36
37pub trait Complete {
38    type Output;
39    type Error;
40
41    fn complete(self) -> Result<Self::Output, Self::Error>;
42}
43
44impl Complete for PartialRequest {
45    type Output = Request;
46    type Error = Error;
47
48    fn complete(self) -> Result<Self::Output, Self::Error> {
49        let PartialRequest { jsonrpc, id, call } = self;
50        if let Some(part_call) = call {
51            part_call
52                .complete()
53                .map(|full_call| Request::new(jsonrpc, id, full_call))
54        } else {
55            Err(Error::method_not_found())
56        }
57    }
58}
59
60macro_rules! partial_call_complete {
61    ($( ($enum_name:ident, $params_name:ident: $params_list:expr, $result_type:ident) ),+ ,) => {
62        partial_call_complete!($( ($enum_name, $params_name) ),+);
63    };
64    ($( ($enum_name:ident, $params_name:ident) ),+) => {
65        impl Complete for PartialCall {
66            type Output = Call;
67            type Error = Error;
68
69            fn complete(self) -> Result<Self::Output, Self::Error> {
70                match self {
71                    $(
72                        PartialCall::$enum_name { params } => {
73                            if let Some(params) = params {
74                                let pparams: PartialParams = serde_json::from_value(params.clone())?;
75                                if pparams.len() < $params_name::required_len()
76                                    && pparams.len() > $params_name::valid_len() {
77                                    Err(Error::invalid_params_len())
78                                } else {
79                                    Ok(Call::$enum_name{ params: serde_json::from_value(params)? })
80                                }
81                            } else {
82                                if $params_name::required_len() == 0 {
83                                    Ok(Call::$enum_name{
84                                        params: serde_json::from_value(
85                                                    serde_json::Value::Array(Vec::new()))?})
86                                } else {
87                                    Err(Error::invalid_params("params is requeired"))
88                                }
89                            }
90                        },
91                    )+
92                }
93            }
94        }
95    }
96}
97
98impl_for_each_jsonrpc_requests!(partial_call_complete);
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103    use ethereum_types::H256;
104
105    #[test]
106    fn test_get_transaction_receipt_params_complete() {
107        let params = GetTransactionReceiptParams::new(H256::from(10).into());
108        let full_req = params.into_request(1);
109
110        let req_str = r#"{
111            "jsonrpc": "2.0",
112            "id": 1,
113            "method": "getTransactionReceipt",
114            "params": ["0x000000000000000000000000000000000000000000000000000000000000000a"]
115        }"#;
116        let part_req = serde_json::from_str::<PartialRequest>(&req_str).unwrap();
117        assert_eq!(part_req.complete().unwrap(), full_req);
118    }
119
120    #[test]
121    fn test_get_transaction_receipt_params_complete_error() {
122        let req_str = r#"{
123            "jsonrpc": "2.0",
124            "id": null,
125            "method": "getTransactionReceipt"
126        }"#;
127        let part_req = serde_json::from_str::<PartialRequest>(&req_str).unwrap();
128
129        assert_eq!(
130            part_req.complete().err().unwrap(),
131            Error::invalid_params("params is requeired")
132        );
133
134        let req_str = r#"{
135            "jsonrpc": "2.0",
136            "id": null,
137            "method": "getTransactionReceipt",
138            "params": [1, 2]
139        }"#;
140        let part_req = serde_json::from_str::<PartialRequest>(&req_str).unwrap();
141        assert_eq!(
142            part_req.complete().err().unwrap(),
143            Error::invalid_params_len()
144        );
145    }
146
147    #[test]
148    fn test_block_number_params_complete() {
149        let params = eth_blockNumberParams::new();
150        let full_req = params.into_request(2);
151
152        let req_str = r#"{
153            "jsonrpc": "2.0",
154            "id": 2,
155            "method": "blockNumber"
156        }"#;
157        let part_req = serde_json::from_str::<PartialRequest>(&req_str).unwrap();
158        assert_eq!(part_req.complete().unwrap(), full_req);
159    }
160
161    #[test]
162    fn test_method_not_found_complete_error() {
163        let req_str = r#"{
164            "jsonrpc": "2.0",
165            "id": null,
166            "params": ["0x000000000000000000000000000000000000000000000000000000000000000a"]
167        }"#;
168        let part_req = serde_json::from_str::<PartialRequest>(&req_str).unwrap();
169
170        assert_eq!(
171            part_req.complete().err().unwrap(),
172            Error::method_not_found()
173        );
174
175        let req_str = r#"{
176            "jsonrpc": "2.0",
177            "id": null,
178            "method": "notAMethod",
179            "params": ["0x000000000000000000000000000000000000000000000000000000000000000a"]
180        }"#;
181        let part_req = serde_json::from_str::<PartialRequest>(&req_str).unwrap();
182        assert_eq!(
183            part_req.complete().err().unwrap(),
184            Error::method_not_found()
185        );
186    }
187}