Prechádzať zdrojové kódy

darkfid: Add RPC endpoint to retrieve WASM bincode

Also updates the params.get() RPC code patterns.
x 7 mesiacov pred
rodič
commit
0fd57636ea

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

@@ -40,6 +40,7 @@ pub enum RpcError {
     ContractZkasDbNotFound = -32200,
     ContractStateNotFound = -32201,
     ContractStateKeyNotFound = -32202,
+    ContractWasmNotFound = -32203,
 
     // Miner configuration errors
     MinerInvalidWalletConfig = -32301,
@@ -108,6 +109,7 @@ fn to_tuple(e: RpcError) -> (i32, String) {
         RpcError::ContractZkasDbNotFound => "zkas database not found for given contract",
         RpcError::ContractStateNotFound => "Records not found for given contract state",
         RpcError::ContractStateKeyNotFound => "Value not found for given contract state key",
+        RpcError::ContractWasmNotFound => "wasm bincode not found for given contract",
 
         // Miner configuration errors
         RpcError::MinerInvalidWalletConfig => "Request wallet configuration is invalid",

+ 63 - 10
bin/darkfid/src/rpc/blockchain.rs

@@ -96,7 +96,9 @@ 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 {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(InvalidParams, None, id).into()
+        };
         if params.len() != 1 || !params[0].is_string() {
             return JsonError::new(InvalidParams, None, id).into()
         }
@@ -136,7 +138,9 @@ 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 {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(InvalidParams, None, id).into()
+        };
         if !params.is_empty() {
             return JsonError::new(InvalidParams, None, id).into()
         }
@@ -171,7 +175,9 @@ impl DarkfiNode {
         id: u16,
         params: JsonValue,
     ) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(InvalidParams, None, id).into()
+        };
         if !params.is_empty() {
             return JsonError::new(InvalidParams, None, id).into()
         }
@@ -195,7 +201,9 @@ 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 {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(InvalidParams, None, id).into()
+        };
         if !params.is_empty() {
             return JsonError::new(InvalidParams, None, id).into()
         }
@@ -220,7 +228,9 @@ 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 {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(InvalidParams, None, id).into()
+        };
         if !params.is_empty() {
             return JsonError::new(InvalidParams, None, id).into()
         }
@@ -239,7 +249,9 @@ 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 {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(InvalidParams, None, id).into()
+        };
         if !params.is_empty() {
             return JsonError::new(InvalidParams, None, id).into()
         }
@@ -260,7 +272,9 @@ 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 {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(InvalidParams, None, id).into()
+        };
         if !params.is_empty() {
             return JsonError::new(InvalidParams, None, id).into()
         }
@@ -286,7 +300,9 @@ 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 {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(InvalidParams, None, id).into()
+        };
         if params.len() != 1 || !params[0].is_string() {
             return JsonError::new(InvalidParams, None, id).into()
         }
@@ -337,6 +353,39 @@ impl DarkfiNode {
         JsonResponse::new(JsonValue::Array(ret), id).into()
     }
 
+    // RPCAPI:
+    // Perform a lookup of a WASM contract binary deployed on-chain and
+    // return the base64-encoded binary.
+    //
+    // **Params:**
+    // * `array[0]`: base58-encoded contract ID string
+    //
+    // **Returns:**
+    // * `String`: base64-encoded WASM binary
+    //
+    // --> {"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 {
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(InvalidParams, None, id).into()
+        };
+        if params.len() != 1 || !params[0].is_string() {
+            return JsonError::new(InvalidParams, None, id).into()
+        }
+
+        let contract_id = params[0].get::<String>().unwrap();
+        let Ok(contract_id) = ContractId::from_str(contract_id) else {
+            return server_error(RpcError::ParseError, id, None)
+        };
+
+        let Ok(bincode) = self.validator.blockchain.contracts.get(contract_id) else {
+            return server_error(RpcError::ContractWasmNotFound, id, None)
+        };
+
+        let encoded = base64::encode(&bincode);
+        JsonResponse::new(encoded.to_string().into(), id).into()
+    }
+
     // RPCAPI:
     // Queries the blockchain database for a given contract state records.
     // Returns the records value raw bytes as a `BTreeMap`.
@@ -351,7 +400,9 @@ 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 {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(InvalidParams, None, id).into()
+        };
         if params.len() != 2 || !params[0].is_string() || !params[1].is_string() {
             return JsonError::new(InvalidParams, None, id).into()
         }
@@ -403,7 +454,9 @@ impl DarkfiNode {
         id: u16,
         params: JsonValue,
     ) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(InvalidParams, None, id).into()
+        };
         if params.len() != 3 ||
             !params[0].is_string() ||
             !params[1].is_string() ||

+ 7 - 2
bin/darkfid/src/rpc/mod.rs

@@ -75,6 +75,7 @@ impl RequestHandler<DefaultRpcHandler> for DarkfiNode {
             "blockchain.last_confirmed_block" => self.blockchain_last_confirmed_block(req.id, req.params).await,
             "blockchain.best_fork_next_block_height" => self.blockchain_best_fork_next_block_height(req.id, req.params).await,
             "blockchain.block_target" => self.blockchain_block_target(req.id, req.params).await,
+            "blockchain.lookup_wasm" => self.blockchain_lookup_wasm(req.id, req.params).await,
             "blockchain.lookup_zkas" => self.blockchain_lookup_zkas(req.id, req.params).await,
             "blockchain.get_contract_state" => self.blockchain_get_contract_state(req.id, req.params).await,
             "blockchain.get_contract_state_key" => self.blockchain_get_contract_state_key(req.id, req.params).await,
@@ -123,7 +124,9 @@ impl DarkfiNode {
     // --> {"jsonrpc": "2.0", "method": "dnet.switch", "params": [true], "id": 1}
     // <-- {"jsonrpc": "2.0", "result": true, "id": 1}
     async fn dnet_switch(&self, id: u16, params: JsonValue) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(ErrorCode::InvalidParams, None, id).into()
+        };
         if params.len() != 1 || !params[0].is_bool() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
         }
@@ -162,7 +165,9 @@ impl DarkfiNode {
     //       ]
     //     }
     pub async fn dnet_subscribe_events(&self, id: u16, params: JsonValue) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(ErrorCode::InvalidParams, None, id).into()
+        };
         if !params.is_empty() {
             return JsonError::new(ErrorCode::InvalidParams, None, id).into()
         }

+ 15 - 5
bin/darkfid/src/rpc/tx.rs

@@ -41,7 +41,9 @@ 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 {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(InvalidParams, None, id).into()
+        };
         if params.len() != 1 || !params[0].is_string() {
             return JsonError::new(InvalidParams, None, id).into()
         }
@@ -92,7 +94,9 @@ 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 {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(InvalidParams, None, id).into()
+        };
         if params.len() != 1 || !params[0].is_string() {
             return JsonError::new(InvalidParams, None, id).into()
         }
@@ -142,7 +146,9 @@ 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 {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(InvalidParams, None, id).into()
+        };
         if !params.is_empty() {
             return JsonError::new(InvalidParams, None, id).into()
         }
@@ -173,7 +179,9 @@ impl DarkfiNode {
     // --> {"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: u16, params: JsonValue) -> JsonResult {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(InvalidParams, None, id).into()
+        };
         if !params.is_empty() {
             return JsonError::new(InvalidParams, None, id).into()
         }
@@ -210,7 +218,9 @@ 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 {
-        let params = params.get::<Vec<JsonValue>>().unwrap();
+        let Some(params) = params.get::<Vec<JsonValue>>() else {
+            return JsonError::new(InvalidParams, None, id).into()
+        };
         if params.len() != 2 || !params[0].is_string() || !params[1].is_bool() {
             return JsonError::new(InvalidParams, None, id).into()
         }