diff --git a/bin/darkfid/src/rpc_blockchain.rs b/bin/darkfid/src/rpc_blockchain.rs index ebea1073e..e1f290069 100644 --- a/bin/darkfid/src/rpc_blockchain.rs +++ b/bin/darkfid/src/rpc_blockchain.rs @@ -90,10 +90,10 @@ impl Darkfid { // // **Returns:** // * Serialized [`Transaction`](https://darkrenaissance.github.io/darkfi/development/darkfi/tx/struct.Transaction.html) - // object + // object encoded with base64 // // --> {"jsonrpc": "2.0", "method": "blockchain.get_tx", "params": ["TxHash"], "id": 1} - // <-- {"jsonrpc": "2.0", "result": {...}, "id": 1} + // <-- {"jsonrpc": "2.0", "result": "ABCD...", "id": 1} pub async fn blockchain_get_tx(&self, id: u16, params: JsonValue) -> JsonResult { let params = params.get::>().unwrap(); if params.len() != 1 || !params[0].is_string() { diff --git a/bin/darkfid2/Cargo.toml b/bin/darkfid2/Cargo.toml index b081b6fff..d1e21ba22 100644 --- a/bin/darkfid2/Cargo.toml +++ b/bin/darkfid2/Cargo.toml @@ -25,7 +25,7 @@ sled = "0.34.7" # JSON-RPC async-trait = "0.1.73" -serde_json = "1.0.105" +tinyjson = "2.5.1" url = "2.4.0" # Daemon diff --git a/bin/darkfid2/src/error.rs b/bin/darkfid2/src/error.rs index 178a70566..3a655559a 100644 --- a/bin/darkfid2/src/error.rs +++ b/bin/darkfid2/src/error.rs @@ -16,8 +16,6 @@ * along with this program. If not, see . */ -use serde_json::Value; - use darkfi::rpc::jsonrpc::{ErrorCode::ServerError, JsonError, JsonResult}; /// Custom RPC errors available for darkfid. @@ -38,7 +36,7 @@ pub enum RpcError { ContractZkasDbNotFound = -32200, } -fn to_tuple(e: RpcError) -> (i64, String) { +fn to_tuple(e: RpcError) -> (i32, String) { let msg = match e { // Transaction-related errors RpcError::TxSimulationFail => "Failed simulating transaction state change", @@ -52,10 +50,10 @@ fn to_tuple(e: RpcError) -> (i64, String) { RpcError::ContractZkasDbNotFound => "zkas database not found for given contract", }; - (e as i64, msg.to_string()) + (e as i32, msg.to_string()) } -pub fn server_error(e: RpcError, id: Value, msg: Option<&str>) -> JsonResult { +pub fn server_error(e: RpcError, id: u16, msg: Option<&str>) -> JsonResult { let (code, default_msg) = to_tuple(e); if let Some(message) = msg { diff --git a/bin/darkfid2/src/main.rs b/bin/darkfid2/src/main.rs index 45525e903..4187b7351 100644 --- a/bin/darkfid2/src/main.rs +++ b/bin/darkfid2/src/main.rs @@ -28,7 +28,7 @@ use darkfi::{ blockchain::BlockInfo, cli_desc, net::{settings::SettingsOpt, P2pPtr}, - rpc::{jsonrpc::MethodSubscriber, server::listen_and_serve}, + rpc::{jsonrpc::JsonSubscriber, server::listen_and_serve}, util::time::TimeKeeper, validator::{Validator, ValidatorConfig, ValidatorPtr}, Result, @@ -110,7 +110,7 @@ pub struct Darkfid { /// Validator(node) pointer validator: ValidatorPtr, /// A map of various subscribers exporting live info from the blockchain - subscribers: HashMap<&'static str, MethodSubscriber>, + subscribers: HashMap<&'static str, JsonSubscriber>, } impl Darkfid { @@ -118,7 +118,7 @@ impl Darkfid { sync_p2p: P2pPtr, consensus_p2p: Option, validator: ValidatorPtr, - subscribers: HashMap<&'static str, MethodSubscriber>, + subscribers: HashMap<&'static str, JsonSubscriber>, ) -> Self { Self { sync_p2p, consensus_p2p, validator, subscribers } } @@ -157,11 +157,10 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { // Here we initialize various subscribers that can export live blockchain/consensus data. let mut subscribers = HashMap::new(); - subscribers.insert("blocks", MethodSubscriber::new("blockchain.subscribe_blocks".into())); - subscribers.insert("txs", MethodSubscriber::new("blockchain.subscribe_txs".into())); + subscribers.insert("blocks", JsonSubscriber::new("blockchain.subscribe_blocks")); + subscribers.insert("txs", JsonSubscriber::new("blockchain.subscribe_txs")); if args.consensus { - subscribers - .insert("proposals", MethodSubscriber::new("blockchain.subscribe_proposals".into())); + subscribers.insert("proposals", JsonSubscriber::new("blockchain.subscribe_proposals")); } // Initialize syncing P2P network diff --git a/bin/darkfid2/src/proto/protocol_block.rs b/bin/darkfid2/src/proto/protocol_block.rs index 4235ed683..3cb41d510 100644 --- a/bin/darkfid2/src/proto/protocol_block.rs +++ b/bin/darkfid2/src/proto/protocol_block.rs @@ -29,7 +29,7 @@ use darkfi::{ ChannelPtr, Message, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr, ProtocolJobsManager, ProtocolJobsManagerPtr, }, - rpc::jsonrpc::MethodSubscriber, + rpc::jsonrpc::JsonSubscriber, validator::ValidatorPtr, Result, }; @@ -53,7 +53,7 @@ pub struct ProtocolBlock { validator: ValidatorPtr, p2p: P2pPtr, channel_address: Url, - subscriber: MethodSubscriber, + subscriber: JsonSubscriber, } impl ProtocolBlock { @@ -61,7 +61,7 @@ impl ProtocolBlock { channel: ChannelPtr, validator: ValidatorPtr, p2p: P2pPtr, - subscriber: MethodSubscriber, + subscriber: JsonSubscriber, ) -> Result { debug!( target: "validator::protocol_block::init", @@ -124,7 +124,7 @@ impl ProtocolBlock { match self.validator.write().await.append_block(&block_copy.0).await { Ok(()) => { self.p2p.broadcast_with_exclude(&block_copy, &exclude_list).await; - self.subscriber.notify(&block_copy).await; + self.subscriber.notify(&[block_copy]).await; } Err(e) => { debug!( diff --git a/bin/darkfid2/src/proto/protocol_proposal.rs b/bin/darkfid2/src/proto/protocol_proposal.rs index b14ba70fd..b639aaeba 100644 --- a/bin/darkfid2/src/proto/protocol_proposal.rs +++ b/bin/darkfid2/src/proto/protocol_proposal.rs @@ -28,7 +28,7 @@ use darkfi::{ ChannelPtr, Message, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr, ProtocolJobsManager, ProtocolJobsManagerPtr, }, - rpc::jsonrpc::MethodSubscriber, + rpc::jsonrpc::JsonSubscriber, validator::{consensus::Proposal, ValidatorPtr}, Result, }; @@ -46,7 +46,7 @@ pub struct ProtocolProposal { validator: ValidatorPtr, p2p: P2pPtr, channel_address: Url, - subscriber: MethodSubscriber, + subscriber: JsonSubscriber, } impl ProtocolProposal { @@ -54,7 +54,7 @@ impl ProtocolProposal { channel: ChannelPtr, validator: ValidatorPtr, p2p: P2pPtr, - subscriber: MethodSubscriber, + subscriber: JsonSubscriber, ) -> Result { debug!( target: "validator::protocol_proposal::init", @@ -114,7 +114,7 @@ impl ProtocolProposal { match self.validator.write().await.consensus.append_proposal(&proposal_copy.0).await { Ok(()) => { self.p2p.broadcast_with_exclude(&proposal_copy, &exclude_list).await; - self.subscriber.notify(&proposal_copy).await; + self.subscriber.notify(&[proposal_copy]).await; } Err(e) => { debug!( diff --git a/bin/darkfid2/src/proto/protocol_tx.rs b/bin/darkfid2/src/proto/protocol_tx.rs index 5e29adb9e..5f6c2e3fc 100644 --- a/bin/darkfid2/src/proto/protocol_tx.rs +++ b/bin/darkfid2/src/proto/protocol_tx.rs @@ -28,7 +28,7 @@ use darkfi::{ ChannelPtr, Message, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr, ProtocolJobsManager, ProtocolJobsManagerPtr, }, - rpc::jsonrpc::MethodSubscriber, + rpc::jsonrpc::JsonSubscriber, tx::Transaction, validator::ValidatorPtr, Result, @@ -47,7 +47,7 @@ pub struct ProtocolTx { validator: ValidatorPtr, p2p: P2pPtr, channel_address: Url, - subscriber: MethodSubscriber, + subscriber: JsonSubscriber, } impl ProtocolTx { @@ -55,7 +55,7 @@ impl ProtocolTx { channel: ChannelPtr, validator: ValidatorPtr, p2p: P2pPtr, - subscriber: MethodSubscriber, + subscriber: JsonSubscriber, ) -> Result { debug!( target: "validator::protocol_tx::init", @@ -110,7 +110,7 @@ impl ProtocolTx { match self.validator.write().await.append_tx(&tx_copy.0).await { Ok(()) => { self.p2p.broadcast_with_exclude(&tx_copy, &exclude_list).await; - self.subscriber.notify(&tx_copy).await; + self.subscriber.notify(&[tx_copy]).await; } Err(e) => { debug!( diff --git a/bin/darkfid2/src/rpc.rs b/bin/darkfid2/src/rpc.rs index 192eda23b..8d472bca6 100644 --- a/bin/darkfid2/src/rpc.rs +++ b/bin/darkfid2/src/rpc.rs @@ -18,10 +18,9 @@ use async_trait::async_trait; use log::debug; -use serde_json::{json, Value}; +use tinyjson::JsonValue; use darkfi::{ - net, rpc::{ jsonrpc::{ErrorCode, JsonError, JsonRequest, JsonResponse, JsonResult}, server::RequestHandler, @@ -34,80 +33,62 @@ use crate::Darkfid; #[async_trait] impl RequestHandler for Darkfid { async fn handle_request(&self, req: JsonRequest) -> JsonResult { - if req.params.as_array().is_none() { - return JsonError::new(ErrorCode::InvalidRequest, None, req.id).into() - } - - let params = req.params.as_array().unwrap(); - - debug!(target: "darkfid::rpc", "--> {}", serde_json::to_string(&req).unwrap()); + debug!(target: "darkfid::rpc", "--> {}", req.stringify().unwrap()); match req.method.as_str() { // ===================== // Miscellaneous methods // ===================== - Some("ping") => return self.pong(req.id, params).await, - Some("clock") => return self.clock(req.id, params).await, - Some("sync_dnet_switch") => return self.sync_dnet_switch(req.id, params).await, - Some("sync_dnet_info") => return self.sync_dnet_info(req.id, params).await, - Some("consensus_dnet_switch") => { - return self.consensus_dnet_switch(req.id, params).await - } - Some("consensus_dnet_info") => return self.consensus_dnet_info(req.id, params).await, + "ping" => return self.pong(req.id, req.params).await, + "clock" => return self.clock(req.id, req.params).await, + "sync_dnet_switch" => return self.sync_dnet_switch(req.id, req.params).await, + "consensus_dnet_switch" => return self.consensus_dnet_switch(req.id, req.params).await, // ================== // Blockchain methods // ================== - Some("blockchain.get_slot") => return self.blockchain_get_slot(req.id, params).await, - Some("blockchain.get_tx") => return self.blockchain_get_tx(req.id, params).await, - Some("blockchain.last_known_slot") => { - return self.blockchain_last_known_slot(req.id, params).await + "blockchain.get_slot" => return self.blockchain_get_slot(req.id, req.params).await, + "blockchain.get_tx" => return self.blockchain_get_tx(req.id, req.params).await, + "blockchain.last_known_slot" => { + return self.blockchain_last_known_slot(req.id, req.params).await } - Some("blockchain.lookup_zkas") => { - return self.blockchain_lookup_zkas(req.id, params).await + "blockchain.lookup_zkas" => { + return self.blockchain_lookup_zkas(req.id, req.params).await } - Some("blockchain.subscribe_blocks") => { - return self.blockchain_subscribe_blocks(req.id, params).await + "blockchain.subscribe_blocks" => { + return self.blockchain_subscribe_blocks(req.id, req.params).await } - Some("blockchain.subscribe_txs") => { - return self.blockchain_subscribe_txs(req.id, params).await + "blockchain.subscribe_txs" => { + return self.blockchain_subscribe_txs(req.id, req.params).await } - Some("blockchain.subscribe_proposals") => { - return self.blockchain_subscribe_proposals(req.id, params).await + "blockchain.subscribe_proposals" => { + return self.blockchain_subscribe_proposals(req.id, req.params).await } // =================== // Transaction methods // =================== - Some("tx.simulate") => return self.tx_simulate(req.id, params).await, - Some("tx.broadcast") => return self.tx_broadcast(req.id, params).await, - Some("tx.pending") => return self.tx_pending(req.id, params).await, - Some("tx.clean_pending") => return self.tx_pending(req.id, params).await, + "tx.simulate" => return self.tx_simulate(req.id, req.params).await, + "tx.broadcast" => return self.tx_broadcast(req.id, req.params).await, + "tx.pending" => return self.tx_pending(req.id, req.params).await, + "tx.clean_pending" => return self.tx_pending(req.id, req.params).await, // ============== // Invalid method // ============== - Some(_) | None => JsonError::new(ErrorCode::MethodNotFound, None, req.id).into(), + _ => JsonError::new(ErrorCode::MethodNotFound, None, req.id).into(), } } } impl Darkfid { // RPCAPI: - // Replies to a ping method. - // --> {"jsonrpc": "2.0", "method": "ping", "params": [], "id": 42} - // <-- {"jsonrpc": "2.0", "result": "pong", "id": 42} - async fn pong(&self, id: Value, _params: &[Value]) -> JsonResult { - JsonResponse::new(json!("pong"), id).into() - } - - // RPCAPI: - // Returns current system clock in `Timestamp` format. + // Returns current system clock as `u64` (String) timestamp. // // --> {"jsonrpc": "2.0", "method": "clock", "params": [], "id": 1} - // <-- {"jsonrpc": "2.0", "result": {...}, "id": 1} - async fn clock(&self, id: Value, _params: &[Value]) -> JsonResult { - JsonResponse::new(json!(Timestamp::current_time()), id).into() + // <-- {"jsonrpc": "2.0", "result": "1234", "id": 1} + async fn clock(&self, id: u16, _params: JsonValue) -> JsonResult { + JsonResponse::new(JsonValue::String(Timestamp::current_time().0.to_string()), id).into() } // RPCAPI: @@ -117,28 +98,21 @@ impl Darkfid { // // --> {"jsonrpc": "2.0", "method": "sync_dnet_switch", "params": [true], "id": 42} // <-- {"jsonrpc": "2.0", "result": true, "id": 42} - async fn sync_dnet_switch(&self, id: Value, params: &[Value]) -> JsonResult { - if params.len() != 1 && params[0].as_bool().is_none() { + async fn sync_dnet_switch(&self, id: u16, params: JsonValue) -> JsonResult { + let params = params.get::>().unwrap(); + if params.len() != 1 || !params[0].is_bool() { return JsonError::new(ErrorCode::InvalidParams, None, id).into() } - if params[0].as_bool().unwrap() { + let switch = params[0].get::().unwrap(); + + if *switch { self.sync_p2p.dnet_enable().await; } else { self.sync_p2p.dnet_disable().await; } - JsonResponse::new(json!(true), id).into() - } - - // RPCAPI: - // Retrieves sync P2P network information. - // - // --> {"jsonrpc": "2.0", "method": "sync_dnet_info", "params": [], "id": 42} - // <-- {"jsonrpc": "2.0", result": {"nodeID": [], "nodeinfo": [], "id": 42} - async fn sync_dnet_info(&self, id: Value, _params: &[Value]) -> JsonResult { - let dnet_info = self.sync_p2p.dnet_info().await; - JsonResponse::new(net::P2p::map_dnet_info(dnet_info), id).into() + JsonResponse::new(JsonValue::Boolean(true), id).into() } // RPCAPI: @@ -148,33 +122,21 @@ impl Darkfid { // // --> {"jsonrpc": "2.0", "method": "consensus_dnet_switch", "params": [true], "id": 42} // <-- {"jsonrpc": "2.0", "result": true, "id": 42} - async fn consensus_dnet_switch(&self, id: Value, params: &[Value]) -> JsonResult { - if params.len() != 1 && params[0].as_bool().is_none() { + async fn consensus_dnet_switch(&self, id: u16, params: JsonValue) -> JsonResult { + let params = params.get::>().unwrap(); + if params.len() != 1 || !params[0].is_bool() { return JsonError::new(ErrorCode::InvalidParams, None, id).into() } if self.consensus_p2p.is_some() { - if params[0].as_bool().unwrap() { + let switch = params[0].get::().unwrap(); + if *switch { self.consensus_p2p.clone().unwrap().dnet_enable().await; } else { self.consensus_p2p.clone().unwrap().dnet_disable().await; } } - JsonResponse::new(json!(true), id).into() - } - - // RPCAPI: - // Retrieves consensus P2P network information. - // - // --> {"jsonrpc": "2.0", "method": "consensus_dnet_info", "params": [], "id": 42} - // <-- {"jsonrpc": "2.0", result": {"nodeID": [], "nodeinfo": [], "id": 42} - async fn consensus_dnet_info(&self, id: Value, _params: &[Value]) -> JsonResult { - let dnet_info = if self.consensus_p2p.is_some() { - self.consensus_p2p.clone().unwrap().dnet_info().await - } else { - vec![] - }; - JsonResponse::new(net::P2p::map_dnet_info(dnet_info), id).into() + JsonResponse::new(JsonValue::Boolean(true), id).into() } } diff --git a/bin/darkfid2/src/rpc_blockchain.rs b/bin/darkfid2/src/rpc_blockchain.rs index 81e9ec44b..66c05f899 100644 --- a/bin/darkfid2/src/rpc_blockchain.rs +++ b/bin/darkfid2/src/rpc_blockchain.rs @@ -21,14 +21,15 @@ use std::str::FromStr; use darkfi_sdk::crypto::ContractId; use darkfi_serial::{deserialize, serialize}; use log::{debug, error}; -use serde_json::{json, Value}; +use tinyjson::JsonValue; use darkfi::{ rpc::jsonrpc::{ ErrorCode::{InternalError, InvalidParams, ParseError}, - JsonError, JsonResponse, JsonResult, JsonSubscriber, + JsonError, JsonResponse, JsonResult, }, runtime::vm_runtime::SMART_CONTRACT_ZKAS_DB_NAME, + util::encoding::base64, }; use crate::{server_error, Darkfid, RpcError}; @@ -39,20 +40,24 @@ impl Darkfid { // Returns a readable block upon success. // // **Params:** - // * `array[0]`: `u64` slot ID + // * `array[0]`: `u64` slot ID (as string) // // **Returns:** // * [`BlockInfo`](https://darkrenaissance.github.io/darkfi/development/darkfi/consensus/block/struct.BlockInfo.html) - // struct as a JSON object + // struct serialized into base64. // - // --> {"jsonrpc": "2.0", "method": "blockchain.get_slot", "params": [0], "id": 1} + // --> {"jsonrpc": "2.0", "method": "blockchain.get_slot", "params": ["0"], "id": 1} // <-- {"jsonrpc": "2.0", "result": {...}, "id": 1} - pub async fn blockchain_get_slot(&self, id: Value, params: &[Value]) -> JsonResult { - if params.len() != 1 || !params[0].is_u64() { + pub async fn blockchain_get_slot(&self, id: u16, params: JsonValue) -> JsonResult { + let params = params.get::>().unwrap(); + if params.len() != 1 || !params[0].is_string() { return JsonError::new(InvalidParams, None, id).into() } - let slot = params[0].as_u64().unwrap(); + let slot = match u64::from_str_radix(params[0].get::().unwrap(), 10) { + Ok(v) => v, + Err(_) => return JsonError::new(ParseError, None, id).into(), + }; let blocks = match self.validator.read().await.blockchain.get_blocks_by_slot(&[slot]) { Ok(v) => v, @@ -66,7 +71,8 @@ impl Darkfid { return server_error(RpcError::UnknownSlot, id, None) } - JsonResponse::new(json!(serialize(&blocks[0])), id).into() + let block = base64::encode(&serialize(&blocks[0])); + JsonResponse::new(JsonValue::String(block), id).into() } // RPCAPI: @@ -78,25 +84,20 @@ impl Darkfid { // // **Returns:** // * Serialized [`Transaction`](https://darkrenaissance.github.io/darkfi/development/darkfi/tx/struct.Transaction.html) - // object + // object encoded with base64 // // --> {"jsonrpc": "2.0", "method": "blockchain.get_tx", "params": ["TxHash"], "id": 1} - // <-- {"jsonrpc": "2.0", "result": {...}, "id": 1} - pub async fn blockchain_get_tx(&self, id: Value, params: &[Value]) -> JsonResult { + // <-- {"jsonrpc": "2.0", "result": "ABCD...", "id": 1} + pub async fn blockchain_get_tx(&self, id: u16, params: JsonValue) -> JsonResult { + let params = params.get::>().unwrap(); if params.len() != 1 { return JsonError::new(InvalidParams, None, id).into() } - let tx_hash_str = if let Some(tx_hash_str) = params[0].as_str() { - tx_hash_str - } else { - return JsonError::new(InvalidParams, None, id).into() - }; - - let tx_hash = if let Ok(tx_hash) = blake3::Hash::from_hex(tx_hash_str) { - tx_hash - } else { - return JsonError::new(ParseError, None, id).into() + let tx_hash = params[0].get::().unwrap(); + let tx_hash = match blake3::Hash::from_hex(tx_hash) { + Ok(v) => v, + Err(_) => return JsonError::new(ParseError, None, id).into(), }; let txs = match self.validator.read().await.blockchain.transactions.get(&[tx_hash], true) { @@ -111,7 +112,8 @@ impl Darkfid { // and strict was used during .get() let tx = txs[0].as_ref().unwrap(); - JsonResponse::new(json!(serialize(tx)), id).into() + let tx_enc = base64::encode(&serialize(tx)); + JsonResponse::new(JsonValue::String(tx_enc), id).into() } // RPCAPI: @@ -121,11 +123,12 @@ impl Darkfid { // * `None` // // **Returns:** - // * `u64` ID of the last known slot + // * `u64` ID of the last known slot, as string // // --> {"jsonrpc": "2.0", "method": "blockchain.last_known_slot", "params": [], "id": 1} - // <-- {"jsonrpc": "2.0", "result": 1234, "id": 1} - pub async fn blockchain_last_known_slot(&self, id: Value, params: &[Value]) -> JsonResult { + // <-- {"jsonrpc": "2.0", "result": "1234", "id": 1} + pub async fn blockchain_last_known_slot(&self, id: u16, params: JsonValue) -> JsonResult { + let params = params.get::>().unwrap(); if !params.is_empty() { return JsonError::new(InvalidParams, None, id).into() } @@ -135,7 +138,7 @@ impl Darkfid { return JsonError::new(InternalError, None, id).into() }; - JsonResponse::new(json!(last_slot.0), id).into() + JsonResponse::new(JsonValue::String(last_slot.0.to_string()), id).into() } // RPCAPI: @@ -145,14 +148,13 @@ impl Darkfid { // // --> {"jsonrpc": "2.0", "method": "blockchain.subscribe_blocks", "params": [], "id": 1} // <-- {"jsonrpc": "2.0", "method": "blockchain.subscribe_blocks", "params": [`blockinfo`]} - pub async fn blockchain_subscribe_blocks(&self, id: Value, params: &[Value]) -> JsonResult { + pub async fn blockchain_subscribe_blocks(&self, id: u16, params: JsonValue) -> JsonResult { + let params = params.get::>().unwrap(); if !params.is_empty() { return JsonError::new(InvalidParams, None, id).into() } - let blocks_subscriber = self.subscribers.get("blocks").unwrap().clone(); - - JsonSubscriber::new(blocks_subscriber).into() + self.subscribers.get("blocks").unwrap().clone().into() } // RPCAPI: @@ -162,14 +164,13 @@ impl Darkfid { // // --> {"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: Value, params: &[Value]) -> JsonResult { + pub async fn blockchain_subscribe_txs(&self, id: u16, params: JsonValue) -> JsonResult { + let params = params.get::>().unwrap(); if !params.is_empty() { return JsonError::new(InvalidParams, None, id).into() } - let txs_subscriber = self.subscribers.get("txs").unwrap().clone(); - - JsonSubscriber::new(txs_subscriber).into() + self.subscribers.get("txs").unwrap().clone().into() } // RPCAPI: @@ -179,7 +180,8 @@ impl Darkfid { // // --> {"jsonrpc": "2.0", "method": "blockchain.subscribe_proposals", "params": [], "id": 1} // <-- {"jsonrpc": "2.0", "method": "blockchain.subscribe_proposals", "params": [`blockinfo`]} - pub async fn blockchain_subscribe_proposals(&self, id: Value, params: &[Value]) -> JsonResult { + pub async fn blockchain_subscribe_proposals(&self, id: u16, params: JsonValue) -> JsonResult { + let params = params.get::>().unwrap(); if !params.is_empty() { return JsonError::new(InvalidParams, None, id).into() } @@ -192,7 +194,7 @@ impl Darkfid { return JsonError::new(InternalError, None, id).into() } - JsonSubscriber::new(proposals_subscriber.unwrap().clone()).into() + proposals_subscriber.unwrap().clone().into() } // RPCAPI: @@ -208,13 +210,15 @@ impl Darkfid { // object // // --> {"jsonrpc": "2.0", "method": "blockchain.lookup_zkas", "params": ["6Ef42L1KLZXBoxBuCDto7coi9DA2D2SRtegNqNU4sd74"], "id": 1} - // <-- {"jsonrpc": "2.0", "result": [["Foo", [...]], ["Bar", [...]]], "id": 1} - pub async fn blockchain_lookup_zkas(&self, id: Value, params: &[Value]) -> JsonResult { + // <-- {"jsonrpc": "2.0", "result": [["Foo", "ABCD..."], ["Bar", "EFGH..."]], "id": 1} + pub async fn blockchain_lookup_zkas(&self, id: u16, params: JsonValue) -> JsonResult { + let params = params.get::>().unwrap(); if params.len() != 1 || !params[0].is_string() { return JsonError::new(InvalidParams, None, id).into() } - let contract_id = match ContractId::from_str(params[0].as_str().unwrap()) { + let contract_id = params[0].get::().unwrap(); + let contract_id = match ContractId::from_str(contract_id) { Ok(v) => v, Err(e) => { error!(target: "darkfid::rpc::blockchain_lookup_zkas", "Error decoding string to ContractId: {}", e); @@ -236,7 +240,7 @@ impl Darkfid { return server_error(RpcError::ContractZkasDbNotFound, id, None) }; - let mut ret: Vec<(String, Vec)> = vec![]; + let mut ret = vec![]; for i in zkas_db.iter() { debug!(target: "darkfid::rpc::blockchain_lookup_zkas", "Iterating over zkas db"); @@ -249,15 +253,13 @@ impl Darkfid { return JsonError::new(InternalError, None, id).into() }; - let Ok((zkas_bincode, _)): Result<(Vec, Vec), std::io::Error> = - deserialize(&zkas_bytes) - else { - return JsonError::new(InternalError, None, id).into() - }; - - ret.push((zkas_ns, zkas_bincode.to_vec())); + let zkas_bincode = base64::encode(&zkas_bytes); + ret.push(JsonValue::Array(vec![ + JsonValue::String(zkas_ns), + JsonValue::String(zkas_bincode), + ])); } - JsonResponse::new(json!(ret), id).into() + JsonResponse::new(JsonValue::Array(ret), id).into() } } diff --git a/bin/darkfid2/src/rpc_tx.rs b/bin/darkfid2/src/rpc_tx.rs index 0083866db..b4fc359eb 100644 --- a/bin/darkfid2/src/rpc_tx.rs +++ b/bin/darkfid2/src/rpc_tx.rs @@ -18,7 +18,7 @@ use darkfi_serial::deserialize; use log::error; -use serde_json::{json, Value}; +use tinyjson::JsonValue; use darkfi::{ rpc::jsonrpc::{ @@ -26,6 +26,7 @@ use darkfi::{ JsonError, JsonResponse, JsonResult, }, tx::Transaction, + util::encoding::base64, }; use super::Darkfid; @@ -37,9 +38,10 @@ impl Darkfid { // Returns `true` if the transaction is valid, otherwise, a corresponding // error. // - // --> {"jsonrpc": "2.0", "method": "tx.simulate", "params": ["base58encodedTX"], "id": 1} + // --> {"jsonrpc": "2.0", "method": "tx.simulate", "params": ["base64encodedTX"], "id": 1} // <-- {"jsonrpc": "2.0", "result": true, "id": 1} - pub async fn tx_simulate(&self, id: Value, params: &[Value]) -> JsonResult { + pub async fn tx_simulate(&self, id: u16, params: JsonValue) -> JsonResult { + let params = params.get::>().unwrap(); if params.len() != 1 || !params[0].is_string() { return JsonError::new(InvalidParams, None, id).into() } @@ -50,10 +52,11 @@ impl Darkfid { } // Try to deserialize the transaction - let tx_bytes = match bs58::decode(params[0].as_str().unwrap().trim()).into_vec() { - Ok(v) => v, - Err(e) => { - error!(target: "darkfid::rpc::tx_simulate", "Failed decoding base58 transaction: {}", e); + let tx_enc = params[0].get::().unwrap().trim(); + let tx_bytes = match base64::decode(tx_enc) { + Some(v) => v, + None => { + error!(target: "darkfid::rpc::tx_simulate", "Failed decoding base64 transaction"); return server_error(RpcError::ParseError, id, None) } }; @@ -78,7 +81,7 @@ impl Darkfid { return server_error(RpcError::TxSimulationFail, id, None) }; - JsonResponse::new(json!(true), id).into() + JsonResponse::new(JsonValue::Boolean(true), id).into() } // RPCAPI: @@ -87,9 +90,10 @@ impl Darkfid { // if the transaction is actually valid, and in turn it will return an // error if this is the case. Otherwise, a transaction ID will be returned. // - // --> {"jsonrpc": "2.0", "method": "tx.broadcast", "params": ["base58encodedTX"], "id": 1} + // --> {"jsonrpc": "2.0", "method": "tx.broadcast", "params": ["base64encodedTX"], "id": 1} // <-- {"jsonrpc": "2.0", "result": "txID...", "id": 1} - pub async fn tx_broadcast(&self, id: Value, params: &[Value]) -> JsonResult { + pub async fn tx_broadcast(&self, id: u16, params: JsonValue) -> JsonResult { + let params = params.get::>().unwrap(); if params.len() != 1 || !params[0].is_string() { return JsonError::new(InvalidParams, None, id).into() } @@ -100,10 +104,11 @@ impl Darkfid { } // Try to deserialize the transaction - let tx_bytes = match bs58::decode(params[0].as_str().unwrap().trim()).into_vec() { - Ok(v) => v, - Err(e) => { - error!(target: "darkfid::rpc::tx_broadcast", "Failed decoding base58 transaction: {}", e); + let tx_enc = params[0].get::().unwrap().trim(); + let tx_bytes = match base64::decode(tx_enc) { + Some(v) => v, + None => { + error!(target: "darkfid::rpc::tx_broadcast", "Failed decoding base64 transaction"); return server_error(RpcError::ParseError, id, None) } }; @@ -145,16 +150,17 @@ impl Darkfid { } let tx_hash = tx.hash().to_string(); - JsonResponse::new(json!(tx_hash), id).into() + JsonResponse::new(JsonValue::String(tx_hash), id).into() } // RPCAPI: // Queries the node pending transactions store to retrieve all transactions. - // Returns a vector of serialized `Transaction` objects. + // Returns a vector of hex-encoded transaction hashes. // // --> {"jsonrpc": "2.0", "method": "tx.pending", "params": [], "id": 1} // <-- {"jsonrpc": "2.0", "result": "[TxHash,...]", "id": 1} - pub async fn tx_pending(&self, id: Value, params: &[Value]) -> JsonResult { + pub async fn tx_pending(&self, id: u16, params: JsonValue) -> JsonResult { + let params = params.get::>().unwrap(); if !params.is_empty() { return JsonError::new(InvalidParams, None, id).into() } @@ -171,17 +177,21 @@ impl Darkfid { return JsonError::new(InternalError, None, id).into() } }; - let pending_txs: Vec = pending_txs.iter().map(|x| x.hash().to_string()).collect(); - JsonResponse::new(json!(pending_txs), id).into() + + let pending_txs: Vec = + pending_txs.iter().map(|x| JsonValue::String(x.hash().to_string())).collect(); + + JsonResponse::new(JsonValue::Array(pending_txs), id).into() } // RPCAPI: // Queries the node pending transactions store to remove all transactions. - // Returns a vector of serialized `Transaction` objects. + // Returns a vector of hex-encoded transaction hashes. // // --> {"jsonrpc": "2.0", "method": "tx.clean_pending", "params": [], "id": 1} // <-- {"jsonrpc": "2.0", "result": "[TxHash,...]", "id": 1} - pub async fn tx_clean_pending(&self, id: Value, params: &[Value]) -> JsonResult { + pub async fn tx_clean_pending(&self, id: u16, params: JsonValue) -> JsonResult { + let params = params.get::>().unwrap(); if !params.is_empty() { return JsonError::new(InvalidParams, None, id).into() } @@ -204,7 +214,9 @@ impl Darkfid { return JsonError::new(InternalError, None, id).into() }; - let pending_txs: Vec = pending_txs.iter().map(|x| x.hash().to_string()).collect(); - JsonResponse::new(json!(pending_txs), id).into() + let pending_txs: Vec = + pending_txs.iter().map(|x| JsonValue::String(x.hash().to_string())).collect(); + + JsonResponse::new(JsonValue::Array(pending_txs), id).into() } } diff --git a/bin/darkfid2/src/task/sync.rs b/bin/darkfid2/src/task/sync.rs index 3baf4c96f..71cf7f4eb 100644 --- a/bin/darkfid2/src/task/sync.rs +++ b/bin/darkfid2/src/task/sync.rs @@ -70,7 +70,7 @@ pub async fn sync_task(node: &Darkfid) -> Result<()> { // Notify subscriber for block in &response.blocks { - notif_sub.notify(block).await; + notif_sub.notify(&[block.clone()]).await; } let last_received = node.validator.read().await.blockchain.last()?; diff --git a/bin/darkfid2/src/utils.rs b/bin/darkfid2/src/utils.rs index 43b11c025..d117f05c5 100644 --- a/bin/darkfid2/src/utils.rs +++ b/bin/darkfid2/src/utils.rs @@ -23,7 +23,7 @@ use log::info; use darkfi::{ error::TxVerifyFailed, net::{P2p, P2pPtr, Settings, SESSION_ALL}, - rpc::jsonrpc::MethodSubscriber, + rpc::jsonrpc::JsonSubscriber, tx::Transaction, validator::ValidatorPtr, Result, @@ -75,7 +75,7 @@ pub fn genesis_txs_total(txs: &[Transaction]) -> Result { pub async fn spawn_sync_p2p( settings: &Settings, validator: &ValidatorPtr, - subscribers: &HashMap<&'static str, MethodSubscriber>, + subscribers: &HashMap<&'static str, JsonSubscriber>, ) -> P2pPtr { info!(target: "darkfid", "Registering sync network P2P protocols..."); let p2p = P2p::new(settings.clone()).await; @@ -116,7 +116,7 @@ pub async fn spawn_sync_p2p( pub async fn spawn_consensus_p2p( settings: &Settings, validator: &ValidatorPtr, - subscribers: &HashMap<&'static str, MethodSubscriber>, + subscribers: &HashMap<&'static str, JsonSubscriber>, ) -> P2pPtr { info!(target: "darkfid", "Registering consensus network P2P protocols..."); let p2p = P2p::new(settings.clone()).await;