diff --git a/docs/rpc-endpoints.md b/docs/rpc-endpoints.md index 9f722273f8..fe4094e7f5 100644 --- a/docs/rpc-endpoints.md +++ b/docs/rpc-endpoints.md @@ -16,15 +16,16 @@ Returns JSON data in the form: ``` { - "balance": 100, + "balance": "0x100..", "nonce": 1, - "balanceProof": "01fa...", - "nonceProof": "01ab...", + "balanceProof": "0x01fa...", + "nonceProof": "0x01ab...", } ``` -Where balance (a u128) and nonce (a u64) are both integers, and the proofs are provided as -hex strings. +Where balance is the hex encoding of a unsigned 128-bit integer +(big-endian), nonce is a unsigned 64-bit integer, and the proofs are +provided as hex strings. For non-existent accounts, this _does not_ 404, rather it returns an object with balance and nonce of 0. @@ -44,8 +45,8 @@ Returns JSON data in the form: ``` { - "data": "01ce...", - "proof": "01ab...", + "data": "0x01ce...", + "proof": "0x01ab...", } ``` @@ -220,7 +221,7 @@ published in, and the MARF proof for the data. { "source": "(define-private ...", "publishHeight": 1, - "proof": "00213..." + "proof": "0x00213..." } ``` @@ -238,7 +239,7 @@ the simulated `tx-sender` are supplied via the POST body in the following JSON f ``` { "sender": "SP31DA6FTSJX2WGTZ69SFY11BH51NZMB0ZW97B5P0.get-info", - "arguments": [ "0011...", "00231..." ] + "arguments": [ "0x0011...", "0x00231..." ] } ``` @@ -250,7 +251,7 @@ This endpoint returns a JSON object of the following form: ``` { "okay": true, - "result": "0011..." + "result": "0x0011..." } ``` diff --git a/src/net/mod.rs b/src/net/mod.rs index c8f58d047b..78c6b3f349 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -858,7 +858,7 @@ pub struct CallReadOnlyResponse { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct AccountEntryResponse { - pub balance: u128, + pub balance: String, pub nonce: u64, #[serde(skip_serializing_if = "Option::is_none")] #[serde(default)] diff --git a/src/net/rpc.rs b/src/net/rpc.rs index 69aebafe9a..e8496b80b9 100644 --- a/src/net/rpc.rs +++ b/src/net/rpc.rs @@ -374,8 +374,8 @@ impl ConversationHttp { let data = chainstate.with_read_only_clarity_tx(cur_burn, cur_block, |clarity_tx| { clarity_tx.with_clarity_db_readonly(|clarity_db| { let key = ClarityDatabase::make_key_for_account_balance(&account); - let (balance, balance_proof) = clarity_db.get_with_proof(&key) - .map(|(a, b)| (a, b.to_hex())) + let (balance, balance_proof) = clarity_db.get_with_proof::(&key) + .map(|(a, b)| (a, format!("0x{}", b.to_hex()))) .unwrap_or_else(|| (0, "".into())); let balance_proof = if with_proof { Some(balance_proof) @@ -384,7 +384,7 @@ impl ConversationHttp { }; let key = ClarityDatabase::make_key_for_account_nonce(&account); let (nonce, nonce_proof) = clarity_db.get_with_proof(&key) - .map(|(a, b)| (a, b.to_hex())) + .map(|(a, b)| (a, format!("0x{}", b.to_hex()))) .unwrap_or_else(|| (0, "".into())); let nonce_proof = if with_proof { Some(nonce_proof) @@ -392,6 +392,7 @@ impl ConversationHttp { None }; + let balance = format!("0x{}", to_hex(&balance.to_be_bytes())); AccountEntryResponse { balance, nonce, balance_proof, nonce_proof } }) }); @@ -413,7 +414,7 @@ impl ConversationHttp { clarity_tx.with_clarity_db_readonly(|clarity_db| { let key = ClarityDatabase::make_key_for_data_map_entry(&contract_identifier, map_name, key); let (value, marf_proof) = clarity_db.get_with_proof::(&key) - .map(|(a, b)| (a, b.to_hex())) + .map(|(a, b)| (a, format!("0x{}", b.to_hex()))) .unwrap_or_else(|| (Value::none(), "".into())); let marf_proof = if with_proof { Some(marf_proof) @@ -421,7 +422,7 @@ impl ConversationHttp { None }; - let data = value.serialize(); + let data = format!("0x{}", value.serialize()); MapEntryResponse { data, marf_proof } }) }); @@ -452,7 +453,7 @@ impl ConversationHttp { let response = match data { Ok(data) => - CallReadOnlyResponse { okay: true, result: Some(data.serialize()), cause: None }, + CallReadOnlyResponse { okay: true, result: Some(format!("0x{}", data.serialize())), cause: None }, Err(e) => CallReadOnlyResponse { okay: false, result: None, cause: Some(e.to_string()) }, }; diff --git a/src/vm/tests/integrations.rs b/src/vm/tests/integrations.rs index 05cc367618..b37277e92c 100644 --- a/src/vm/tests/integrations.rs +++ b/src/vm/tests/integrations.rs @@ -187,8 +187,6 @@ fn integration_test_get_info() { conf.burnchain.block_time = 1500; - let contract_sk = StacksPrivateKey::new(); - let num_rounds = 4; let mut run_loop = testnet::helium::RunLoop::new(conf); @@ -356,7 +354,7 @@ fn integration_test_get_info() { .json(&key.serialize()) .send() .unwrap().json::>().unwrap(); - let result_data = Value::try_deserialize_hex_untyped(&res["data"]).unwrap(); + let result_data = Value::try_deserialize_hex_untyped(&res["data"][2..]).unwrap(); let expected_data = chain_state.clarity_eval_read_only(bhh, &contract_identifier, "(some (get-exotic-data-info u1))"); assert!(res.get("proof").is_some()); @@ -371,7 +369,7 @@ fn integration_test_get_info() { .json(&key.serialize()) .send() .unwrap().json::>().unwrap(); - let result_data = Value::try_deserialize_hex_untyped(&res["data"]).unwrap(); + let result_data = Value::try_deserialize_hex_untyped(&res["data"][2..]).unwrap(); assert_eq!(result_data, Value::none()); let sender_addr = to_addr(&StacksPrivateKey::from_hex(SK_3).unwrap()); @@ -390,7 +388,7 @@ fn integration_test_get_info() { .unwrap().json::>().unwrap(); assert!(res.get("proof").is_none()); - let result_data = Value::try_deserialize_hex_untyped(&res["data"]).unwrap(); + let result_data = Value::try_deserialize_hex_untyped(&res["data"][2..]).unwrap(); let expected_data = chain_state.clarity_eval_read_only(bhh, &contract_identifier, "(some (get-exotic-data-info u1))"); eprintln!("{}", serde_json::to_string(&res).unwrap()); @@ -411,7 +409,7 @@ fn integration_test_get_info() { .unwrap().json::>().unwrap(); assert!(res.get("proof").is_some()); - let result_data = Value::try_deserialize_hex_untyped(&res["data"]).unwrap(); + let result_data = Value::try_deserialize_hex_untyped(&res["data"][2..]).unwrap(); let expected_data = chain_state.clarity_eval_read_only(bhh, &contract_identifier, "(some (get-exotic-data-info u1))"); eprintln!("{}", serde_json::to_string(&res).unwrap()); @@ -423,7 +421,7 @@ fn integration_test_get_info() { &http_origin, &sender_addr); eprintln!("Test: GET {}", path); let res = client.get(&path).send().unwrap().json::().unwrap(); - assert_eq!(res.balance, 100000); + assert_eq!(u128::from_str_radix(&res.balance[2..], 16).unwrap(), 100000); assert_eq!(res.nonce, 3); assert!(res.nonce_proof.is_some()); assert!(res.balance_proof.is_some()); @@ -433,7 +431,7 @@ fn integration_test_get_info() { &http_origin, &contract_addr); eprintln!("Test: GET {}", path); let res = client.get(&path).send().unwrap().json::().unwrap(); - assert_eq!(res.balance, 0); + assert_eq!(u128::from_str_radix(&res.balance[2..], 16).unwrap(), 0); assert_eq!(res.nonce, 1); assert!(res.nonce_proof.is_some()); assert!(res.balance_proof.is_some()); @@ -443,7 +441,7 @@ fn integration_test_get_info() { &http_origin, ADDR_4); eprintln!("Test: GET {}", path); let res = client.get(&path).send().unwrap().json::().unwrap(); - assert_eq!(res.balance, 300); + assert_eq!(u128::from_str_radix(&res.balance[2..], 16).unwrap(), 300); assert_eq!(res.nonce, 0); assert!(res.nonce_proof.is_some()); assert!(res.balance_proof.is_some()); @@ -453,7 +451,7 @@ fn integration_test_get_info() { &http_origin, &contract_addr); eprintln!("Test: GET {}", path); let res = client.get(&path).send().unwrap().json::().unwrap(); - assert_eq!(res.balance, 0); + assert_eq!(u128::from_str_radix(&res.balance[2..], 16).unwrap(), 0); assert_eq!(res.nonce, 0); assert!(res.nonce_proof.is_some()); assert!(res.balance_proof.is_some()); @@ -462,7 +460,7 @@ fn integration_test_get_info() { &http_origin, ADDR_4); eprintln!("Test: GET {}", path); let res = client.get(&path).send().unwrap().json::().unwrap(); - assert_eq!(res.balance, 300); + assert_eq!(u128::from_str_radix(&res.balance[2..], 16).unwrap(), 300); assert_eq!(res.nonce, 0); assert!(res.nonce_proof.is_none()); assert!(res.balance_proof.is_none()); @@ -471,7 +469,7 @@ fn integration_test_get_info() { &http_origin, ADDR_4); eprintln!("Test: GET {}", path); let res = client.get(&path).send().unwrap().json::().unwrap(); - assert_eq!(res.balance, 300); + assert_eq!(u128::from_str_radix(&res.balance[2..], 16).unwrap(), 300); assert_eq!(res.nonce, 0); assert!(res.nonce_proof.is_some()); assert!(res.balance_proof.is_some()); @@ -543,7 +541,7 @@ fn integration_test_get_info() { assert!(res.get("cause").is_none()); assert!(res["okay"].as_bool().unwrap()); - let result_data = Value::try_deserialize_hex_untyped(res["result"].as_str().unwrap()).unwrap(); + let result_data = Value::try_deserialize_hex_untyped(&res["result"].as_str().unwrap()[2..]).unwrap(); let expected_data = chain_state.clarity_eval_read_only(bhh, &contract_identifier, "(get-exotic-data-info u1)"); assert_eq!(result_data, expected_data); diff --git a/src/vm/types/serialization.rs b/src/vm/types/serialization.rs index 34a704cbf7..c148743510 100644 --- a/src/vm/types/serialization.rs +++ b/src/vm/types/serialization.rs @@ -475,6 +475,11 @@ impl Value { } pub fn try_deserialize_hex_untyped(hex: &str) -> Result { + let hex = if hex.starts_with("0x") { + &hex[2..] + } else { + &hex + }; let mut data = hex_bytes(hex) .map_err(|_| "Bad hex string")?; Value::try_deserialize_bytes_untyped(&mut data) @@ -765,6 +770,9 @@ mod tests { assert_eq!( expected, &Value::try_deserialize_hex_untyped(test)); + assert_eq!( + expected, + &Value::try_deserialize_hex_untyped(&format!("0x{}", test))); } }