Browse Source

rpc/jsonrpc: Use i64 ids instead of u16

x 2 months ago
parent
commit
676e10eaa0

+ 2 - 2
bin/darkfid/src/error.rs

@@ -172,7 +172,7 @@ fn to_tuple(e: RpcError) -> (i32, String) {
     (e as i32, msg.to_string())
 }
 
-pub fn server_error(e: RpcError, id: u16, msg: Option<&str>) -> JsonResult {
+pub fn server_error(e: RpcError, id: i64, msg: Option<&str>) -> JsonResult {
     let (code, default_msg) = to_tuple(e);
 
     if let Some(message) = msg {
@@ -182,7 +182,7 @@ pub fn server_error(e: RpcError, id: u16, msg: Option<&str>) -> JsonResult {
     JsonError::new(ServerError(code), Some(default_msg), id).into()
 }
 
-pub fn miner_status_response(id: u16, status: &str) -> JsonResult {
+pub fn miner_status_response(id: i64, status: &str) -> JsonResult {
     JsonResponse::new(
         JsonValue::from(HashMap::from([(
             "status".to_string(),

+ 13 - 13
bin/darkfid/src/rpc/blockchain.rs

@@ -53,7 +53,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "blockchain.get_block", "params": [0], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": "base64encodedblock", "id": 1}
-    pub async fn blockchain_get_block(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn blockchain_get_block(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -101,7 +101,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "blockchain.get_tx", "params": ["TxHash"], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": "base64encodedtx", "id": 1}
-    pub async fn blockchain_get_tx(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn blockchain_get_tx(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -144,7 +144,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "blockchain.get_difficulty", "params": [1], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": [123, 456], "id": 1}
-    pub async fn blockchain_get_difficulty(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn blockchain_get_difficulty(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -184,7 +184,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "blockchain.last_confirmed_block", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": [1234, "HeaderHash"], "id": 1}
-    pub async fn blockchain_last_confirmed_block(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn blockchain_last_confirmed_block(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -219,7 +219,7 @@ impl DarkfiNode {
     // <-- {"jsonrpc": "2.0", "result": 1234, "id": 1}
     pub async fn blockchain_best_fork_next_block_height(
         &self,
-        id: u16,
+        id: i64,
         params: JsonValue,
     ) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
@@ -248,7 +248,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "blockchain.block_target", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": 120, "id": 1}
-    pub async fn blockchain_block_target(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn blockchain_block_target(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -275,7 +275,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "blockchain.subscribe_blocks", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "method": "blockchain.subscribe_blocks", "params": ["base64encodedblock"]}
-    pub async fn blockchain_subscribe_blocks(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn blockchain_subscribe_blocks(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -296,7 +296,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "blockchain.subscribe_txs", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "method": "blockchain.subscribe_txs", "params": ["tx_hash"]}
-    pub async fn blockchain_subscribe_txs(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn blockchain_subscribe_txs(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -319,7 +319,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "blockchain.subscribe_proposals", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "method": "blockchain.subscribe_proposals", "params": ["base64encodedblock"]}
-    pub async fn blockchain_subscribe_proposals(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn blockchain_subscribe_proposals(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -347,7 +347,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "blockchain.lookup_zkas", "params": ["BZHKGQ26bzmBithTQYTJtjo2QdCqpkR9tjSBopT4yf4o"], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": [["Foo", "ABCD..."], ["Bar", "EFGH..."]], "id": 1}
-    pub async fn blockchain_lookup_zkas(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn blockchain_lookup_zkas(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -415,7 +415,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "blockchain.lookup_wasm", "params": ["BZHKGQ26bzmBithTQYTJtjo2QdCqpkR9tjSBopT4yf4o"], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": "ABCD...", "id": 1}
-    pub async fn blockchain_lookup_wasm(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn blockchain_lookup_wasm(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -449,7 +449,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "blockchain.get_contract_state", "params": ["BZHK...", "tree"], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": "ABCD...", "id": 1}
-    pub async fn blockchain_get_contract_state(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn blockchain_get_contract_state(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -502,7 +502,7 @@ impl DarkfiNode {
     // <-- {"jsonrpc": "2.0", "result": "ABCD...", "id": 1}
     pub async fn blockchain_get_contract_state_key(
         &self,
-        id: u16,
+        id: i64,
         params: JsonValue,
     ) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {

+ 2 - 2
bin/darkfid/src/rpc/management.rs

@@ -77,7 +77,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "dnet.switch", "params": [true], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
-    pub async fn dnet_switch(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn dnet_switch(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
         };
@@ -118,7 +118,7 @@ impl DarkfiNode {
     //         }
     //       ]
     //     }
-    pub async fn dnet_subscribe_events(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn dnet_subscribe_events(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
         };

+ 1 - 1
bin/darkfid/src/rpc/misc.rs

@@ -31,7 +31,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "clock", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": 1767015913, "id": 1}
-    pub async fn clock(&self, id: u16, _params: JsonValue) -> JsonResult {
+    pub async fn clock(&self, id: i64, _params: JsonValue) -> JsonResult {
         JsonResponse::new((Timestamp::current_time().inner() as f64).into(), id).into()
     }
 }

+ 3 - 3
bin/darkfid/src/rpc/stratum.rs

@@ -120,7 +120,7 @@ impl DarkfiNode {
     //       },
     //       "id": 1
     //     }
-    pub async fn stratum_login(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn stratum_login(&self, id: i64, params: JsonValue) -> JsonResult {
         // Check if node is synced before responding
         let validator = self.validator.read().await;
         if !validator.synced {
@@ -245,7 +245,7 @@ impl DarkfiNode {
     //       "id": 1
     //     }
     // <-- {"jsonrpc": "2.0", "result": {"status": "OK"}, "id": 1}
-    pub async fn stratum_submit(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn stratum_submit(&self, id: i64, params: JsonValue) -> JsonResult {
         // Check if node is synced before responding
         let mut validator = self.validator.write().await;
         if !validator.synced {
@@ -373,7 +373,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "keepalived", "params": {"id": "foo"}, "id": 1}
     // <-- {"jsonrpc": "2.0", "result": {"status": "KEEPALIVED"}, "id": 1}
-    pub async fn stratum_keepalived(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn stratum_keepalived(&self, id: i64, params: JsonValue) -> JsonResult {
         // Parse request params
         let Some(params) = params.get::<HashMap<String, JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()

+ 6 - 6
bin/darkfid/src/rpc/tx.rs

@@ -40,7 +40,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "tx.simulate", "params": ["base64encodedTX"], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
-    pub async fn tx_simulate(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn tx_simulate(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -103,7 +103,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "tx.broadcast", "params": ["base64encodedTX"], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": "txID...", "id": 1}
-    pub async fn tx_broadcast(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn tx_broadcast(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -169,7 +169,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "tx.pending", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": ["TxHash" , "..."], "id": 1}
-    pub async fn tx_pending(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn tx_pending(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -205,7 +205,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "tx.rebroadcast_pending", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
-    pub async fn tx_rebroadcast_pending(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn tx_rebroadcast_pending(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -254,7 +254,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "tx.clean_pending", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
-    pub async fn tx_clean_pending(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn tx_clean_pending(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -284,7 +284,7 @@ impl DarkfiNode {
     //
     // --> {"jsonrpc": "2.0", "method": "tx.calculate_fee", "params": ["base64encodedTX", "include_fee"], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
-    pub async fn tx_calculate_fee(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn tx_calculate_fee(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };

+ 3 - 3
bin/darkfid/src/rpc/xmr.rs

@@ -102,7 +102,7 @@ impl DarkfiNode {
     //       },
     //       "id": 1
     //     }
-    pub async fn xmr_merge_mining_get_chain_id(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn xmr_merge_mining_get_chain_id(&self, id: i64, params: JsonValue) -> JsonResult {
         // Verify request params
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
@@ -185,7 +185,7 @@ impl DarkfiNode {
     //       },
     //       "id": 1
     //     }
-    pub async fn xmr_merge_mining_get_aux_block(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn xmr_merge_mining_get_aux_block(&self, id: i64, params: JsonValue) -> JsonResult {
         // Check if node is synced before responding to p2pool
         let validator = self.validator.read().await;
         if !validator.synced {
@@ -323,7 +323,7 @@ impl DarkfiNode {
     //       "id": 1
     //     }
     // <-- {"jsonrpc":"2.0", "result": {"status": "accepted"}, "id": 1}
-    pub async fn xmr_merge_mining_submit_solution(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn xmr_merge_mining_submit_solution(&self, id: i64, params: JsonValue) -> JsonResult {
         // Check if node is synced before responding to p2pool
         let mut validator = self.validator.write().await;
         if !validator.synced {

+ 6 - 6
bin/darkirc/src/rpc.rs

@@ -67,7 +67,7 @@ impl DarkIrc {
     //
     // --> {"jsonrpc": "2.0", "method": "dnet.switch", "params": [true], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
-    async fn dnet_switch(&self, id: u16, params: JsonValue) -> JsonResult {
+    async fn dnet_switch(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
         };
@@ -93,7 +93,7 @@ impl DarkIrc {
     //
     // --> {"jsonrpc": "2.0", "method": "dnet.subscribe_events", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "method": "dnet.subscribe_events", "params": [`event`]}
-    pub async fn dnet_subscribe_events(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn dnet_subscribe_events(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
         };
@@ -111,7 +111,7 @@ impl DarkIrc {
     //
     // --> {"jsonrpc": "2.0", "method": "deg.subscribe_events", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "method": "deg.subscribe_events", "params": [`event`]}
-    pub async fn deg_subscribe_events(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn deg_subscribe_events(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
         };
@@ -129,7 +129,7 @@ impl DarkIrc {
     //
     // --> {"jsonrpc": "2.0", "method": "deg.switch", "params": [true], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
-    async fn deg_switch(&self, id: u16, params: JsonValue) -> JsonResult {
+    async fn deg_switch(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
         };
@@ -153,7 +153,7 @@ impl DarkIrc {
     //
     // --> {"jsonrpc": "2.0", "method": "deg.switch", "params": [true], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
-    async fn eg_get_info(&self, id: u16, params: JsonValue) -> JsonResult {
+    async fn eg_get_info(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params_) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
         };
@@ -169,7 +169,7 @@ impl DarkIrc {
     //
     // --> {"jsonrpc": "2.0", "method": "eventgraph.replay", "params": ..., "id": 42}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
-    async fn eg_rep_info(&self, id: u16, params: JsonValue) -> JsonResult {
+    async fn eg_rep_info(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params_) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
         };

+ 11 - 11
bin/explorer/src/rpc.rs

@@ -300,7 +300,7 @@ impl CoinbaseInfo {
 }
 
 impl Explorer {
-    pub async fn rpc_current_difficulty(&self, id: u16, _params: JsonValue) -> JsonResult {
+    pub async fn rpc_current_difficulty(&self, id: i64, _params: JsonValue) -> JsonResult {
         // Get latest height
         let Ok(Some(height)) = self.get_height() else {
             return JsonError::new(InternalError, None, id).into()
@@ -320,7 +320,7 @@ impl Explorer {
         .into()
     }
 
-    pub async fn rpc_current_height(&self, id: u16, _params: JsonValue) -> JsonResult {
+    pub async fn rpc_current_height(&self, id: i64, _params: JsonValue) -> JsonResult {
         let Ok(Some(height)) = self.get_height() else {
             return JsonError::new(InternalError, None, id).into()
         };
@@ -328,7 +328,7 @@ impl Explorer {
         JsonResponse::new(JsonValue::Number(height as f64), id).into()
     }
 
-    pub async fn rpc_latest_blocks(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn rpc_latest_blocks(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -369,7 +369,7 @@ impl Explorer {
         JsonResponse::new(JsonValue::Array(blocks), id).into()
     }
 
-    pub async fn rpc_get_block(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn rpc_get_block(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -406,7 +406,7 @@ impl Explorer {
         JsonResponse::new(info.to_json(), id).into()
     }
 
-    pub async fn rpc_get_tx(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn rpc_get_tx(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -432,7 +432,7 @@ impl Explorer {
 
     /// Search for a block or transaction by hash.
     /// Returns `{"type": "block", "height": N}` or `{"type": "tx"}` depending on what was found.
-    pub async fn rpc_search(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn rpc_search(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -483,7 +483,7 @@ impl Explorer {
     /// Calculate the current network hashrate.
     /// Hashrate = difficulty / average_block_time
     /// We use the last N blocks to smooth out variance.
-    pub async fn rpc_get_hashrate(&self, id: u16, _params: JsonValue) -> JsonResult {
+    pub async fn rpc_get_hashrate(&self, id: i64, _params: JsonValue) -> JsonResult {
         const BLOCKS_TO_AVERAGE: u64 = 30;
 
         let Ok(Some(height)) = self.get_height() else {
@@ -529,7 +529,7 @@ impl Explorer {
     /// Get contract information by ID.
     /// Params: `[contract_id: String]`
     /// Returns: `{ contract_id, locked, wasm_size, deploy_block, deploy_tx }`
-    pub async fn rpc_get_contract(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn rpc_get_contract(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
@@ -559,7 +559,7 @@ impl Explorer {
     /// List all contracts.
     /// Params: `[locked_filter: bool | null] (optional)`
     /// Returns: Array of contract objects
-    pub async fn rpc_list_contracts(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn rpc_list_contracts(&self, id: i64, params: JsonValue) -> JsonResult {
         let locked_filter = if let Some(params) = params.get::<Vec<JsonValue>>() {
             if !params.is_empty() {
                 params[0].get::<bool>().copied()
@@ -592,7 +592,7 @@ impl Explorer {
 
     /// Get contract count.
     /// Returns: Number of contracts
-    pub async fn rpc_contract_count(&self, id: u16, _params: JsonValue) -> JsonResult {
+    pub async fn rpc_contract_count(&self, id: i64, _params: JsonValue) -> JsonResult {
         let Ok(count) = self.get_contract_count() else {
             return JsonError::new(InternalError, None, id).into()
         };
@@ -602,7 +602,7 @@ impl Explorer {
 
     /// Get blockchain statistics from stored data.
     /// Returns daily stats, monthly growth, and tx per block stats.
-    pub async fn rpc_get_stats(&self, id: u16, _params: JsonValue) -> JsonResult {
+    pub async fn rpc_get_stats(&self, id: i64, _params: JsonValue) -> JsonResult {
         // Get daily stats from sled
         let daily_stats = match self.get_all_daily_stats().await {
             Ok(stats) => stats,

+ 2 - 2
bin/fud/fud/src/rpc/management.rs

@@ -81,7 +81,7 @@ impl ManagementRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "dnet.switch", "params": [true], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
-    pub async fn dnet_switch(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn dnet_switch(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
         };
@@ -122,7 +122,7 @@ impl ManagementRpcInterface {
     //         }
     //       ]
     //     }
-    pub async fn dnet_subscribe_events(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn dnet_subscribe_events(&self, id: i64, params: JsonValue) -> JsonResult {
         let Some(params) = params.get::<Vec<JsonValue>>() else {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
         };

+ 9 - 9
bin/fud/fud/src/rpc/mod.rs

@@ -95,7 +95,7 @@ impl DefaultRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "put", "params": ["/foo.txt"], "id": 42}
     // <-- {"jsonrpc": "2.0", "result: "df4...3db7", "id": 42}
-    async fn put(&self, id: u16, params: JsonValue) -> JsonResult {
+    async fn put(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if params.len() != 1 || !params[0].is_string() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
@@ -124,7 +124,7 @@ impl DefaultRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "get", "params": ["1211...abfd", "~/myfile.jpg", null], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": "/home/user/myfile.jpg", "id": 42}
-    async fn get(&self, id: u16, params: JsonValue) -> JsonResult {
+    async fn get(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if params.len() != 3 || !params[0].is_string() || !params[1].is_string() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
@@ -188,7 +188,7 @@ impl DefaultRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "get", "params": [], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": `event`, "id": 42}
-    async fn subscribe(&self, _id: u16, _params: JsonValue) -> JsonResult {
+    async fn subscribe(&self, _id: i64, _params: JsonValue) -> JsonResult {
         self.event_sub.clone().into()
     }
 
@@ -197,7 +197,7 @@ impl DefaultRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "list_buckets", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": [[["abcdef", ["tcp://127.0.0.1:9700"]]]], "id": 1}
-    pub async fn list_resources(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn list_resources(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if !params.is_empty() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
@@ -217,7 +217,7 @@ impl DefaultRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "list_buckets", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": [["abcdef", ["tcp://127.0.0.1:9700"]]], "id": 1}
-    pub async fn list_buckets(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn list_buckets(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if !params.is_empty() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
@@ -246,7 +246,7 @@ impl DefaultRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "list_seeders", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": {"seeders": {"abcdefileid": [["abcdef", ["tcp://127.0.0.1:9700"]]]}}, "id": 1}
-    pub async fn list_seeders(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn list_seeders(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if !params.is_empty() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
@@ -277,7 +277,7 @@ impl DefaultRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "remove", "params": ["1211...abfd"], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": [], "id": 1}
-    pub async fn remove(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn remove(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if params.len() != 1 || !params[0].is_string() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
@@ -300,7 +300,7 @@ impl DefaultRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "verify", "params": ["1211...abfd"], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": [], "id": 1}
-    async fn verify(&self, id: u16, params: JsonValue) -> JsonResult {
+    async fn verify(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if !params.iter().all(|param| param.is_string()) {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
@@ -337,7 +337,7 @@ impl DefaultRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "lookup", "params": ["1211...abfd"], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": {"seeders": {"abcdefileid": [["abcdef", ["tcp://127.0.0.1:9701"]]]}}, "id": 1}
-    pub async fn lookup(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn lookup(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if params.len() != 1 || !params[0].is_string() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()

+ 7 - 7
bin/genev/genevd/src/rpc.rs

@@ -104,7 +104,7 @@ impl JsonRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "dnet.subscribe_events", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "method": "dnet.subscribe_events", "params": [`event`]}
-    pub async fn dnet_subscribe_events(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn dnet_subscribe_events(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if !params.is_empty() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
@@ -120,7 +120,7 @@ impl JsonRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "dnet_switch", "params": [true], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
-    async fn dnet_switch(&self, id: u16, params: JsonValue) -> JsonResult {
+    async fn dnet_switch(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if params.len() != 1 || !params[0].is_bool() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
@@ -144,7 +144,7 @@ impl JsonRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "deg.subscribe_events", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "method": "deg.subscribe_events", "params": [`event`]}
-    pub async fn deg_subscribe_events(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn deg_subscribe_events(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if !params.is_empty() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
@@ -160,7 +160,7 @@ impl JsonRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "deg.switch", "params": [true], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
-    async fn deg_switch(&self, id: u16, params: JsonValue) -> JsonResult {
+    async fn deg_switch(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if params.len() != 1 || !params[0].is_bool() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
@@ -182,7 +182,7 @@ impl JsonRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "deg.switch", "params": [true], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
-    async fn eg_get_info(&self, id: u16, params: JsonValue) -> JsonResult {
+    async fn eg_get_info(&self, id: i64, params: JsonValue) -> JsonResult {
         let params_ = params.get::<Vec<JsonValue>>().unwrap();
         if !params_.is_empty() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
@@ -195,7 +195,7 @@ impl JsonRpcInterface {
     // Add a new event
     // --> {"jsonrpc": "2.0", "method": "add", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": [nickname, ...], "id": 1}
-    async fn add(&self, id: u16, params: JsonValue) -> JsonResult {
+    async fn add(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if params.len() != 1 || !params[0].is_string() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
@@ -230,7 +230,7 @@ impl JsonRpcInterface {
     // List events
     // --> {"jsonrpc": "2.0", "method": "list", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": [task_id, ...], "id": 1}
-    async fn list(&self, id: u16, _params: JsonValue) -> JsonResult {
+    async fn list(&self, id: i64, _params: JsonValue) -> JsonResult {
         debug!("Fetching all events");
         let mut seen_events = vec![];
         let dag_events = self.event_graph.order_events().await;

+ 1 - 1
bin/lilith/src/main.rs

@@ -239,7 +239,7 @@ impl Lilith {
     // Returns all spawned networks names with their node addresses.
     // --> {"jsonrpc": "2.0", "method": "spawns", "params": [], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": {"spawns": spawns_info}, "id": 42}
-    async fn spawns(&self, id: u16, _params: JsonValue) -> JsonResult {
+    async fn spawns(&self, id: i64, _params: JsonValue) -> JsonResult {
         let mut spawns = vec![];
         for spawn in &self.networks {
             spawns.push(spawn.info().await);

+ 1 - 1
bin/tau/taud/src/error.rs

@@ -53,7 +53,7 @@ impl From<std::io::Error> for TaudError {
     }
 }
 
-pub fn to_json_result(res: TaudResult<JsonValue>, id: u16) -> JsonResult {
+pub fn to_json_result(res: TaudResult<JsonValue>, id: i64) -> JsonResult {
     match res {
         Ok(v) => JsonResponse::new(v, id).into(),
         Err(err) => match err {

+ 4 - 4
bin/tau/taud/src/jsonrpc.rs

@@ -166,7 +166,7 @@ impl JsonRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "dnet.subscribe_events", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "method": "dnet.subscribe_events", "params": [`event`]}
-    pub async fn dnet_subscribe_events(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn dnet_subscribe_events(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if !params.is_empty() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
@@ -182,7 +182,7 @@ impl JsonRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "deg.subscribe_events", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "method": "deg.subscribe_events", "params": [`event`]}
-    pub async fn deg_subscribe_events(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn deg_subscribe_events(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if !params.is_empty() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
@@ -198,7 +198,7 @@ impl JsonRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "deg.switch", "params": [true], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
-    async fn deg_switch(&self, _id: u16, params: JsonValue) -> TaudResult<JsonValue> {
+    async fn deg_switch(&self, _id: i64, params: JsonValue) -> TaudResult<JsonValue> {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if params.len() != 1 || !params[0].is_bool() {
             return Err(TaudError::InvalidData("Invalid parameters".into()))
@@ -220,7 +220,7 @@ impl JsonRpcInterface {
     //
     // --> {"jsonrpc": "2.0", "method": "deg.switch", "params": [true], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
-    async fn eg_get_info(&self, id: u16, params: JsonValue) -> JsonResult {
+    async fn eg_get_info(&self, id: i64, params: JsonValue) -> JsonResult {
         let params_ = params.get::<Vec<JsonValue>>().unwrap();
         if !params_.is_empty() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()

+ 4 - 4
example/dchat/dchatd/src/rpc.rs

@@ -59,7 +59,7 @@ impl Dchat {
     // TODO
     // --> {"jsonrpc": "2.0", "method": "send", "params": [true], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
-    async fn send(&self, id: u16, params: JsonValue) -> JsonResult {
+    async fn send(&self, id: i64, params: JsonValue) -> JsonResult {
         let msg = params[0].get::<String>().unwrap().to_string();
         let dchatmsg = DchatMsg { msg };
         self.p2p.broadcast(&dchatmsg).await;
@@ -70,7 +70,7 @@ impl Dchat {
     // TODO
     // --> {"jsonrpc": "2.0", "method": "inbox", "params": [true], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
-    async fn recv(&self, id: u16) -> JsonResult {
+    async fn recv(&self, id: i64) -> JsonResult {
         let buffer = self.recv_msgs.lock().await;
         let msgs: Vec<JsonValue> =
             buffer.iter().map(|x| JsonValue::String(x.msg.clone())).collect();
@@ -84,7 +84,7 @@ impl Dchat {
     //
     // --> {"jsonrpc": "2.0", "method": "dnet_switch", "params": [true], "id": 42}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 42}
-    async fn dnet_switch(&self, id: u16, params: JsonValue) -> JsonResult {
+    async fn dnet_switch(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if params.len() != 1 || !params[0].is_bool() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
@@ -108,7 +108,7 @@ impl Dchat {
     //
     // --> {"jsonrpc": "2.0", "method": "dnet.subscribe_events", "params": [], "id": 1}
     // <-- {"jsonrpc": "2.0", "method": "dnet.subscribe_events", "params": [`event`]}
-    pub async fn dnet_subscribe_events(&self, id: u16, params: JsonValue) -> JsonResult {
+    pub async fn dnet_subscribe_events(&self, id: i64, params: JsonValue) -> JsonResult {
         let params = params.get::<Vec<JsonValue>>().unwrap();
         if !params.is_empty() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()

+ 1 - 1
src/event_graph/mod.rs

@@ -1183,7 +1183,7 @@ impl EventGraph {
     }
 
     #[cfg(feature = "rpc")]
-    pub async fn eventgraph_info(&self, id: u16, _params: JsonValue) -> JsonResult {
+    pub async fn eventgraph_info(&self, id: i64, _params: JsonValue) -> JsonResult {
         let current_genesis = self.current_genesis.read().await;
         let dag_name = current_genesis.header.timestamp.to_string();
         let mut graph = HashMap::new();

+ 72 - 44
src/rpc/jsonrpc.rs

@@ -28,6 +28,50 @@ use crate::{
     Result,
 };
 
+/// Parse a JSON field into i64. Accepts numeric values and numeric strings.
+/// Note this is not fully spec-compliant, but the vast majority of RPC
+/// clients use numeric IDs.
+fn parse_id_field(v: &JsonValue, accept_string: bool) -> std::result::Result<i64, RpcError> {
+    let n = if let Some(num) = v.get::<f64>() {
+        *num
+    } else if accept_string {
+        match v.get::<String>() {
+            Some(s) => s
+                .parse::<f64>()
+                .map_err(|_| RpcError::InvalidJson("id string is not numeric".to_string()))?,
+            None => return Err(RpcError::InvalidJson("id is not a number or string".to_string())),
+        }
+    } else {
+        return Err(RpcError::InvalidJson("id is not a number".to_string()))
+    };
+
+    if !n.is_finite() || n.fract() != 0.0 {
+        return Err(RpcError::InvalidJson("id must be a finite integer".to_string()))
+    }
+
+    if n < i64::MIN as f64 || n > i64::MAX as f64 {
+        return Err(RpcError::InvalidJson("id out of i64 range".to_string()))
+    }
+
+    Ok(n as i64)
+}
+
+/// Parse a JSON number into i32 with the same bounds-checking discipline
+fn parse_i32_field(v: &JsonValue, name: &str) -> std::result::Result<i32, RpcError> {
+    let n =
+        *v.get::<f64>().ok_or_else(|| RpcError::InvalidJson(format!("{name} is not a number")))?;
+
+    if !n.is_finite() || n.fract() != 0.0 {
+        return Err(RpcError::InvalidJson(format!("{name} must be a finite integer")))
+    }
+
+    if n < i32::MIN as f64 || n > i32::MAX as f64 {
+        return Err(RpcError::InvalidJson(format!("{name} out of i32 range")))
+    }
+
+    Ok(n as i32)
+}
+
 /// JSON-RPC error codes.
 /// The error codes `[-32768, -32000]` are reserved for predefined errors.
 #[derive(Copy, Clone, Debug)]
@@ -151,7 +195,7 @@ pub struct JsonRequest {
     /// JSON-RPC version
     pub jsonrpc: &'static str,
     /// Request ID
-    pub id: u16,
+    pub id: i64,
     /// Request method
     pub method: String,
     /// Request parameters
@@ -164,7 +208,8 @@ impl JsonRequest {
     /// The request ID is chosen randomly.
     pub fn new(method: &str, params: JsonValue) -> Self {
         assert!(params.is_object() || params.is_array());
-        Self { jsonrpc: "2.0", id: OsRng::gen(&mut OsRng), method: method.to_string(), params }
+        let id: i64 = OsRng::gen_range(&mut OsRng, 0..(1i64 << 53));
+        Self { jsonrpc: "2.0", id, method: method.to_string(), params }
     }
 
     /// Convert the object into a JSON string
@@ -178,7 +223,7 @@ impl From<&JsonRequest> for JsonValue {
     fn from(req: &JsonRequest) -> JsonValue {
         JsonValue::Object(HashMap::from([
             ("jsonrpc".to_string(), JsonValue::String(req.jsonrpc.to_string())),
-            ("id".to_string(), JsonValue::Number(req.id.into())),
+            ("id".to_string(), JsonValue::Number(req.id as f64)),
             ("method".to_string(), JsonValue::String(req.method.clone())),
             ("params".to_string(), req.params.clone()),
         ]))
@@ -233,25 +278,7 @@ impl TryFrom<&JsonValue> for JsonRequest {
             ))
         }
 
-        // HACK ALERT:
-        // Some RPC clients send string IDs. We assume they're numeric, so
-        // here we cast the strings to numbers.
-        let id = if map["id"].is_number() {
-            *map["id"].get::<f64>().unwrap() as u16
-        } else if map["id"].is_string() {
-            match map["id"].get::<String>().unwrap().parse::<f64>() {
-                Ok(v) => v as u16,
-                Err(_) => {
-                    return Err(RpcError::InvalidJson(
-                        "Request does not contain valid \"id\" field".to_string(),
-                    ))
-                }
-            }
-        } else {
-            return Err(RpcError::InvalidJson(
-                "Request does not contain valid \"id\" field".to_string(),
-            ))
-        };
+        let id = parse_id_field(&map["id"], true)?;
 
         Ok(Self {
             jsonrpc: "2.0",
@@ -348,7 +375,7 @@ pub struct JsonResponse {
     /// JSON-RPC version
     pub jsonrpc: &'static str,
     /// Request ID
-    pub id: u16,
+    pub id: i64,
     /// Response result
     pub result: JsonValue,
 }
@@ -356,7 +383,7 @@ pub struct JsonResponse {
 impl JsonResponse {
     /// Create a new [`JsonResponse`] object with the given ID and result value.
     /// Creating a `JsonResponse` implies that the method call was successful.
-    pub fn new(result: JsonValue, id: u16) -> Self {
+    pub fn new(result: JsonValue, id: i64) -> Self {
         Self { jsonrpc: "2.0", id, result }
     }
 
@@ -371,7 +398,7 @@ impl From<&JsonResponse> for JsonValue {
     fn from(rep: &JsonResponse) -> JsonValue {
         JsonValue::Object(HashMap::from([
             ("jsonrpc".to_string(), JsonValue::String(rep.jsonrpc.to_string())),
-            ("id".to_string(), JsonValue::Number(rep.id.into())),
+            ("id".to_string(), JsonValue::Number(rep.id as f64)),
             ("result".to_string(), rep.result.clone()),
         ]))
     }
@@ -410,7 +437,7 @@ impl TryFrom<&JsonValue> for JsonResponse {
 
         Ok(Self {
             jsonrpc: "2.0",
-            id: *map["id"].get::<f64>().unwrap() as u16,
+            id: parse_id_field(&map["id"], false)?,
             result: map["result"].clone(),
         })
     }
@@ -435,7 +462,7 @@ pub struct JsonError {
     /// JSON-RPC version
     pub jsonrpc: &'static str,
     /// Request ID
-    pub id: u16,
+    pub id: i64,
     /// JSON-RPC error (code and message)
     pub error: JsonErrorVal,
 }
@@ -453,7 +480,7 @@ impl JsonError {
     /// Create a new [`JsonError`] object with the given error code, optional
     /// message, and a response ID.
     /// Creating a `JsonError` implies that the method call was unsuccessful.
-    pub fn new(c: ErrorCode, message: Option<String>, id: u16) -> Self {
+    pub fn new(c: ErrorCode, message: Option<String>, id: i64) -> Self {
         let error = JsonErrorVal { code: c.code(), message: message.unwrap_or(c.message()) };
         Self { jsonrpc: "2.0", id, error }
     }
@@ -474,7 +501,7 @@ impl From<&JsonError> for JsonValue {
 
         JsonValue::Object(HashMap::from([
             ("jsonrpc".to_string(), JsonValue::String(err.jsonrpc.to_string())),
-            ("id".to_string(), JsonValue::Number(err.id.into())),
+            ("id".to_string(), JsonValue::Number(err.id as f64)),
             ("error".to_string(), errmap),
         ]))
     }
@@ -524,25 +551,26 @@ impl TryFrom<&JsonValue> for JsonError {
             ))
         }
 
-        if !map["error"]["code"].is_number() {
-            return Err(RpcError::InvalidJson(
-                "Error does not contain valid \"error.code\" field".to_string(),
-            ))
-        }
+        let err_map: &HashMap<String, JsonValue> = map["error"].get().unwrap();
 
-        if !map["error"]["message"].is_string() {
-            return Err(RpcError::InvalidJson(
-                "Error does not contain valid \"error.message\" field".to_string(),
-            ))
-        }
+        let code_val = err_map.get("code").ok_or_else(|| {
+            RpcError::InvalidJson("Error does not contain \"error.code\" field".to_string())
+        })?;
+
+        let message_val = err_map.get("message").ok_or_else(|| {
+            RpcError::InvalidJson("Error does not contain \"error.message\" field".to_string())
+        })?;
+
+        let code = parse_i32_field(code_val, "error.code")?;
+        let message = message_val
+            .get::<String>()
+            .ok_or_else(|| RpcError::InvalidJson("\"error.message\" is not a string".to_string()))?
+            .to_string();
 
         Ok(Self {
             jsonrpc: "2.0",
-            id: *map["id"].get::<f64>().unwrap() as u16,
-            error: JsonErrorVal {
-                code: *map["error"]["code"].get::<f64>().unwrap() as i32,
-                message: map["error"]["message"].get::<String>().unwrap().to_string(),
-            },
+            id: parse_id_field(&map["id"], false)?,
+            error: JsonErrorVal { code, message },
         })
     }
 }

+ 1 - 1
src/rpc/p2p_method.rs

@@ -26,7 +26,7 @@ use crate::net;
 
 #[async_trait]
 pub trait HandlerP2p: Sync + Send {
-    async fn p2p_get_info(&self, id: u16, _params: JsonValue) -> JsonResult {
+    async fn p2p_get_info(&self, id: i64, _params: JsonValue) -> JsonResult {
         let mut channels = Vec::new();
         for channel in self.p2p().hosts().channels() {
             let session = match channel.session_type_id() {

+ 1 - 1
src/rpc/server.rs

@@ -47,7 +47,7 @@ use crate::{
 pub trait RequestHandler<T>: Sync + Send {
     async fn handle_request(&self, req: JsonRequest) -> JsonResult;
 
-    async fn pong(&self, id: u16, _params: JsonValue) -> JsonResult {
+    async fn pong(&self, id: i64, _params: JsonValue) -> JsonResult {
         JsonResponse::new(JsonValue::String("pong".to_string()), id).into()
     }
 

+ 2 - 2
tests/jsonrpc.rs

@@ -47,11 +47,11 @@ struct RpcSrv {
 }
 
 impl RpcSrv {
-    async fn pong(&self, id: u16, _params: JsonValue) -> JsonResult {
+    async fn pong(&self, id: i64, _params: JsonValue) -> JsonResult {
         JsonResponse::new(JsonValue::String("pong".to_string()), id).into()
     }
 
-    async fn kill(&self, id: u16, _params: JsonValue) -> JsonResult {
+    async fn kill(&self, id: i64, _params: JsonValue) -> JsonResult {
         self.stop_sub.0.send(()).await.unwrap();
         JsonResponse::new(JsonValue::String("bye".to_string()), id).into()
     }