From b80693f9cafd9f7bfa0a2a4b9e86c846139f25b9 Mon Sep 17 00:00:00 2001 From: Jesse Schulman Date: Wed, 19 Jun 2024 17:07:15 -0700 Subject: [PATCH 01/26] Changes for ship reading --- crates/antelope/src/api/v1/chain.rs | 8 +++- crates/antelope/src/chain/abi.rs | 6 ++- crates/antelope/src/serializer/packer.rs | 61 ++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/crates/antelope/src/api/v1/chain.rs b/crates/antelope/src/api/v1/chain.rs index 734b86b..2719654 100644 --- a/crates/antelope/src/api/v1/chain.rs +++ b/crates/antelope/src/api/v1/chain.rs @@ -213,13 +213,17 @@ impl ChainAPI { rows.push(row); } - let next_key = TableIndexType::NAME(name!(next_key_str.as_str())); + let next_key = if next_key_str.is_empty() { + None + } else { + Some(TableIndexType::NAME(name!(next_key_str.as_str()))) + }; Ok(GetTableRowsResponse { rows, more, ram_payers: None, - next_key: Some(next_key), + next_key, }) } } diff --git a/crates/antelope/src/chain/abi.rs b/crates/antelope/src/chain/abi.rs index 8fe5527..3559cb0 100644 --- a/crates/antelope/src/chain/abi.rs +++ b/crates/antelope/src/chain/abi.rs @@ -55,6 +55,7 @@ pub struct AbiField { #[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, StructPacker)] pub struct AbiStruct { pub name: String, + #[serde(default)] pub base: String, pub fields: Vec, } @@ -75,8 +76,9 @@ pub struct AbiAction { #[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, StructPacker)] pub struct AbiTable { - #[serde(deserialize_with = "deserialize_name")] - pub name: Name, + //#[serde(deserialize_with = "deserialize_name")] + pub name: String, + #[serde(default)] pub index_type: String, #[serde(default)] pub key_names: Vec, diff --git a/crates/antelope/src/serializer/packer.rs b/crates/antelope/src/serializer/packer.rs index 144419a..a2a3d55 100644 --- a/crates/antelope/src/serializer/packer.rs +++ b/crates/antelope/src/serializer/packer.rs @@ -1,4 +1,5 @@ use core::mem::size_of; +use serde::{Deserialize, Serialize}; use crate::{chain::varint::VarUint32, util::slice_copy}; @@ -296,6 +297,45 @@ impl_packed!(u128); impl_packed!(f32); impl_packed!(f64); +#[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug, Default)] +pub struct Float128 { + /// + pub data: [u8; 16], +} + +impl Float128 { + /// + pub fn new(data: [u8;16]) -> Self { + Self { + data: data + } + } + + /// + pub fn data(&self) -> &[u8; 16] { + return &self.data; + } +} + +impl Packer for Float128 { + fn size(&self) -> usize { + return 16; + } + + fn pack(&self, enc: &mut Encoder) -> usize { + let data = enc.alloc(self.size()); + slice_copy(data, &self.data); + self.size() + } + + fn unpack(&mut self, raw: &[u8]) -> usize { + let size = self.size(); + assert!(raw.len() >= size, "Float128.unpack: buffer overflow!"); + slice_copy(&mut self.data, &raw[..size]); + return self.size(); + } +} + /// Implement `Packer` for `String` type. impl Packer for String { /// Returns the size of this value in bytes. @@ -427,3 +467,24 @@ where dec.get_pos() } } + +/// Implement `Packer` for `Box` type. +impl Packer for Box + where + T: Packer + Default, +{ + /// Returns the size of this value in bytes. + fn size(&self) -> usize { + (**self).size() + } + + /// Packs this value into the given encoder. + fn pack(&self, enc: &mut Encoder) -> usize { + (**self).pack(enc) + } + + /// Unpacks this value from the given data. + fn unpack(&mut self, data: &[u8]) -> usize { + (**self).unpack(data) + } +} From d445a1f82e7f7417de60e5b6a0bae1af5fc07997 Mon Sep 17 00:00:00 2001 From: Jesse Schulman Date: Wed, 19 Jun 2024 17:25:08 -0700 Subject: [PATCH 02/26] Adding support for other index types on next_key --- crates/antelope/src/api/v1/chain.rs | 27 +++++++++++++++++++++++---- crates/antelope/tests/client.rs | 2 +- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/crates/antelope/src/api/v1/chain.rs b/crates/antelope/src/api/v1/chain.rs index 2719654..3570cef 100644 --- a/crates/antelope/src/api/v1/chain.rs +++ b/crates/antelope/src/api/v1/chain.rs @@ -21,6 +21,7 @@ use crate::{ serializer::formatter::{JSONObject, ValueTo}, util::hex_to_bytes, }; +use crate::chain::checksum::{Checksum160, Checksum256}; #[derive(Debug, Default, Clone)] pub struct ChainAPI { @@ -213,10 +214,28 @@ impl ChainAPI { rows.push(row); } - let next_key = if next_key_str.is_empty() { - None - } else { - Some(TableIndexType::NAME(name!(next_key_str.as_str()))) + let mut next_key = None; + + match params.lower_bound { + Some(TableIndexType::NAME(_)) => { + next_key = Some(TableIndexType::NAME(name!(next_key_str.as_str()))); + } + Some(TableIndexType::UINT64(_)) => { + next_key = Some(TableIndexType::UINT64(next_key_str.parse().unwrap())); + } + Some(TableIndexType::UINT128(_)) => { + next_key = Some(TableIndexType::UINT128(next_key_str.parse().unwrap())); + } + Some(TableIndexType::CHECKSUM160(_)) => { + next_key = Some(TableIndexType::CHECKSUM160(Checksum160::from_bytes(hex_to_bytes(&next_key_str).as_slice()).unwrap())); + } + Some(TableIndexType::CHECKSUM256(_)) => { + next_key = Some(TableIndexType::CHECKSUM256(Checksum256::from_bytes(hex_to_bytes(&next_key_str).as_slice()).unwrap())); + } + Some(TableIndexType::FLOAT64(_)) => { + next_key = Some(TableIndexType::FLOAT64(next_key_str.parse().unwrap())); + } + None => {} }; Ok(GetTableRowsResponse { diff --git a/crates/antelope/tests/client.rs b/crates/antelope/tests/client.rs index 934dc77..5adfff2 100644 --- a/crates/antelope/tests/client.rs +++ b/crates/antelope/tests/client.rs @@ -191,7 +191,7 @@ pub async fn chain_get_abi() { // Check tables parsing assert_eq!(abi_object.abi.tables.len(), 2); - assert_eq!(abi_object.abi.tables[0].name, name!("accounts")); + assert_eq!(abi_object.abi.tables[0].name, "accounts"); } #[test] From a3b3adec9f0c5c1ea6997e8975bcf9bf4c343ea8 Mon Sep 17 00:00:00 2001 From: Jesse Schulman Date: Fri, 21 Jun 2024 15:33:16 -0700 Subject: [PATCH 03/26] Fix ABI encoding, better handle secondary index table queries --- crates/antelope/src/api/system/mod.rs | 5 +-- crates/antelope/src/api/v1/chain.rs | 52 +++++++++++++++------------ crates/antelope/src/chain/abi.rs | 4 +-- 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/crates/antelope/src/api/system/mod.rs b/crates/antelope/src/api/system/mod.rs index 400d094..72e0482 100644 --- a/crates/antelope/src/api/system/mod.rs +++ b/crates/antelope/src/api/system/mod.rs @@ -1,5 +1,6 @@ pub mod structs; +use std::path::Path; use crate::api::client::{APIClient, Provider}; use crate::api::system::structs::{ CreateAccountParams, DelegateBandwidthAction, NewAccountAction, SetAbiAction, SetCodeAction, @@ -104,8 +105,8 @@ impl SystemAPI { memo: Option, private_key: PrivateKey, ) -> Result> { - let wasm = std::fs::read(wasm_path).unwrap(); - let abi_json_bytes = std::fs::read(abi_path).unwrap(); + let wasm = std::fs::read(Path::new(wasm_path)).unwrap(); + let abi_json_bytes = std::fs::read(Path::new(abi_path)).unwrap(); let abi: ABI = serde_json::from_slice(&abi_json_bytes).unwrap(); let abi_bytes = Encoder::pack(&abi); self.set_contract(account, wasm, abi_bytes, memo, private_key) diff --git a/crates/antelope/src/api/v1/chain.rs b/crates/antelope/src/api/v1/chain.rs index 3570cef..299ac9c 100644 --- a/crates/antelope/src/api/v1/chain.rs +++ b/crates/antelope/src/api/v1/chain.rs @@ -199,7 +199,11 @@ impl ChainAPI { Some(params.to_json()), ); - let json: Value = serde_json::from_str(result.await.unwrap().as_str()).unwrap(); + let response = match result.await { + Ok(response) => response, + Err(_) => return Err(ClientError::NETWORK("Failed to get table rows".into())), + }; + let json: Value = serde_json::from_str(response.as_str()).unwrap(); let response_obj = JSONObject::new(json); let more = response_obj.get_bool("more")?; let next_key_str = response_obj.get_string("next_key")?; @@ -215,28 +219,30 @@ impl ChainAPI { } let mut next_key = None; - - match params.lower_bound { - Some(TableIndexType::NAME(_)) => { - next_key = Some(TableIndexType::NAME(name!(next_key_str.as_str()))); - } - Some(TableIndexType::UINT64(_)) => { - next_key = Some(TableIndexType::UINT64(next_key_str.parse().unwrap())); - } - Some(TableIndexType::UINT128(_)) => { - next_key = Some(TableIndexType::UINT128(next_key_str.parse().unwrap())); - } - Some(TableIndexType::CHECKSUM160(_)) => { - next_key = Some(TableIndexType::CHECKSUM160(Checksum160::from_bytes(hex_to_bytes(&next_key_str).as_slice()).unwrap())); - } - Some(TableIndexType::CHECKSUM256(_)) => { - next_key = Some(TableIndexType::CHECKSUM256(Checksum256::from_bytes(hex_to_bytes(&next_key_str).as_slice()).unwrap())); - } - Some(TableIndexType::FLOAT64(_)) => { - next_key = Some(TableIndexType::FLOAT64(next_key_str.parse().unwrap())); - } - None => {} - }; + + if !next_key_str.is_empty() { + match params.lower_bound { + Some(TableIndexType::NAME(_)) => { + next_key = Some(TableIndexType::NAME(name!(next_key_str.as_str()))); + } + Some(TableIndexType::UINT64(_)) => { + next_key = Some(TableIndexType::UINT64(next_key_str.parse().unwrap())); + } + Some(TableIndexType::UINT128(_)) => { + next_key = Some(TableIndexType::UINT128(next_key_str.parse().unwrap())); + } + Some(TableIndexType::CHECKSUM160(_)) => { + next_key = Some(TableIndexType::CHECKSUM160(Checksum160::from_bytes(hex_to_bytes(&next_key_str).as_slice()).unwrap())); + } + Some(TableIndexType::CHECKSUM256(_)) => { + next_key = Some(TableIndexType::CHECKSUM256(Checksum256::from_bytes(hex_to_bytes(&next_key_str).as_slice()).unwrap())); + } + Some(TableIndexType::FLOAT64(_)) => { + next_key = Some(TableIndexType::FLOAT64(next_key_str.parse().unwrap())); + } + None => {} + }; + } Ok(GetTableRowsResponse { rows, diff --git a/crates/antelope/src/chain/abi.rs b/crates/antelope/src/chain/abi.rs index 3559cb0..26e81cb 100644 --- a/crates/antelope/src/chain/abi.rs +++ b/crates/antelope/src/chain/abi.rs @@ -76,8 +76,8 @@ pub struct AbiAction { #[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, StructPacker)] pub struct AbiTable { - //#[serde(deserialize_with = "deserialize_name")] - pub name: String, + #[serde(deserialize_with = "deserialize_name")] + pub name: Name, #[serde(default)] pub index_type: String, #[serde(default)] From ad801ce6a11ad1173fe42b74dbe5a9f163194fd9 Mon Sep 17 00:00:00 2001 From: Jesse Schulman Date: Tue, 2 Jul 2024 15:45:12 -0700 Subject: [PATCH 04/26] WIP - Complete GetTableRowsParams to_json functionality --- crates/antelope/src/api/client.rs | 9 +- crates/antelope/src/api/default_provider.rs | 45 +++++++- crates/antelope/src/api/v1/chain.rs | 33 +++++- crates/antelope/src/api/v1/structs.rs | 106 ++++++++++++++++++- crates/antelope/src/chain/checksum.rs | 17 +++ crates/antelope/src/chain/time.rs | 9 ++ crates/antelope/tests/client.rs | 82 +++++++++++++- crates/antelope/tests/utils/mock_provider.rs | 4 + 8 files changed, 295 insertions(+), 10 deletions(-) diff --git a/crates/antelope/src/api/client.rs b/crates/antelope/src/api/client.rs index b549c97..ce16993 100644 --- a/crates/antelope/src/api/client.rs +++ b/crates/antelope/src/api/client.rs @@ -29,6 +29,7 @@ impl Display for HTTPMethod { #[async_trait::async_trait] pub trait Provider: Debug + Default + Sync + Send { + fn set_debug(&mut self, debug: bool); async fn post(&self, path: String, body: Option) -> Result; async fn get(&self, path: String) -> Result; } @@ -40,7 +41,13 @@ pub struct APIClient { impl APIClient

{ pub fn default_provider(base_url: String) -> Result, String> { - let provider = DefaultProvider::new(base_url).unwrap(); + Self::default_provider_debug(base_url, false) + } + + pub fn default_provider_debug(base_url: String, debug: bool) -> Result, String> { + let mut provider = DefaultProvider::new(base_url).unwrap(); + provider.set_debug(debug); + APIClient::custom_provider(provider) } diff --git a/crates/antelope/src/api/default_provider.rs b/crates/antelope/src/api/default_provider.rs index 6c8ce1d..c292b2c 100644 --- a/crates/antelope/src/api/default_provider.rs +++ b/crates/antelope/src/api/default_provider.rs @@ -6,6 +6,7 @@ use crate::api::client::Provider; #[derive(Default, Clone)] pub struct DefaultProvider { + debug: bool, base_url: String, client: Client, } @@ -25,6 +26,7 @@ impl DefaultProvider { let url = base_url.trim_end_matches('/'); Ok(Self { + debug: false, base_url: String::from(url), client: client.unwrap(), }) @@ -40,28 +42,61 @@ impl Debug for DefaultProvider { #[async_trait::async_trait] impl Provider for DefaultProvider { async fn get(&self, path: String) -> Result { + if self.debug { + println!("GET {}", self.base_url.to_string() + &path); + } + let res = self .client .get(self.base_url.to_string() + &path) .send() .await; if res.is_err() { - return Err(res.err().unwrap().to_string()); + let res_err = res.err().unwrap().to_string(); + if self.debug { + println!("Error: {}", res_err); + } + + return Err(res_err); + } + + let response = res.unwrap().text().await.unwrap(); + if self.debug { + println!("Response: {}", response); } - Ok(res.unwrap().text().await.unwrap()) + Ok(response) } async fn post(&self, path: String, body: Option) -> Result { let mut builder = self.client.post(self.base_url.to_string() + &path); if body.is_some() { - builder = builder.body(body.unwrap()); + let body_str = body.unwrap(); + if self.debug { + println!("POST {} {}", self.base_url.to_string() + &path, body_str); + } + + builder = builder.body(body_str); } let res = builder.send().await; if res.is_err() { - return Err(res.err().unwrap().to_string()); + let err_str = res.err().unwrap().to_string(); + if self.debug { + println!("Error: {}", err_str); + } + + return Err(err_str); } - Ok(res.unwrap().text().await.unwrap()) + let response = res.unwrap().text().await.unwrap(); + if self.debug { + println!("Response: {}", response); + } + + Ok(response) + } + + fn set_debug(&mut self, debug: bool) { + self.debug = debug; } } diff --git a/crates/antelope/src/api/v1/chain.rs b/crates/antelope/src/api/v1/chain.rs index 299ac9c..784d704 100644 --- a/crates/antelope/src/api/v1/chain.rs +++ b/crates/antelope/src/api/v1/chain.rs @@ -2,7 +2,7 @@ use std::fmt::Debug; use serde_json::{self, Value}; -use crate::api::v1::structs::{ABIResponse, EncodingError, GetBlockResponse, ServerError}; +use crate::api::v1::structs::{ABIResponse, EncodingError, GetBlockResponse, GetTransactionStatusResponse, ServerError}; use crate::{ api::{ client::Provider, @@ -190,6 +190,37 @@ impl ChainAPI { } } + pub async fn get_transaction_status(&self, trx_id: Checksum256) -> Result> { + let payload = serde_json::json!({ + "id": trx_id, + }); + + let result = self + .provider + .post(String::from("/v1/chain/get_transaction_status"), Some(payload.to_string())) + .await; + + match result { + Ok(response) => { + match serde_json::from_str::(&response) { + Ok(status_response) => Ok(status_response), + Err(_) => { + // Attempt to parse the error response + match serde_json::from_str::(&response) { + Ok(error_response) => Err(ClientError::SERVER(ServerError { + error: error_response, + })), + Err(_) => Err(ClientError::ENCODING(EncodingError { + message: "Failed to parse JSON".into(), + })), + } + } + } + } + Err(msg) => Err(ClientError::NETWORK(msg)), + } + } + pub async fn get_table_rows( &self, params: GetTableRowsParams, diff --git a/crates/antelope/src/api/v1/structs.rs b/crates/antelope/src/api/v1/structs.rs index 6fce093..60ebe71 100644 --- a/crates/antelope/src/api/v1/structs.rs +++ b/crates/antelope/src/api/v1/structs.rs @@ -4,6 +4,8 @@ use serde::de::{self, Visitor}; use serde::{Deserialize, Deserializer, Serialize}; use serde_json::{json, Value}; use std::fmt; +use std::mem::discriminant; +use digest::block_buffer::Block; use crate::chain::abi::ABI; use crate::chain::public_key::PublicKey; @@ -235,6 +237,32 @@ pub struct SendTransactionResponse { pub processed: ProcessedTransaction, } +#[derive(Debug, Serialize, Deserialize)] +pub enum TransactionState { + InBlock, + Irreversible, + LocallyApplied, + ForkedOut, + Unknown, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct GetTransactionStatusResponse { + pub state: TransactionState, + pub block_number: Option, + pub block_id: Option, + pub block_timestamp: Option, + pub expiration: Option, + pub head_number: u32, + pub head_id: BlockId, + pub head_timestamp: TimePoint, + pub irreversible_number: u32, + pub irreversible_id: BlockId, + pub irreversible_timestamp: TimePoint, + pub earliest_tracked_block_id: BlockId, + pub earliest_tracked_block_number: u32, +} + #[derive(Debug, Serialize, Deserialize)] pub struct ActionTrace { pub action_ordinal: u32, @@ -297,6 +325,23 @@ pub enum IndexPosition { TENTH, } +impl IndexPosition { + pub fn to_json(&self) -> Value { + match self { + IndexPosition::PRIMARY => Value::String("primary".to_string()), + IndexPosition::SECONDARY => Value::String("secondary".to_string()), + IndexPosition::TERTIARY => Value::String("tertiary".to_string()), + IndexPosition::FOURTH => Value::String("fourth".to_string()), + IndexPosition::FIFTH => Value::String("fifth".to_string()), + IndexPosition::SIXTH => Value::String("sixth".to_string()), + IndexPosition::SEVENTH => Value::String("seventh".to_string()), + IndexPosition::EIGHTH => Value::String("eighth".to_string()), + IndexPosition::NINTH => Value::String("ninth".to_string()), + IndexPosition::TENTH => Value::String("tenth".to_string()), + } + } +} + #[derive(Debug, Serialize, Deserialize)] pub enum TableIndexType { NAME(Name), @@ -307,6 +352,30 @@ pub enum TableIndexType { CHECKSUM160(Checksum160), } +impl TableIndexType { + pub fn to_json(&self) -> Value { + match self { + TableIndexType::NAME(name) => json!(name.to_string()), + TableIndexType::UINT64(value) => json!(value.to_string()), + TableIndexType::UINT128(value) => json!(value.to_string()), + TableIndexType::FLOAT64(value) => json!(value.to_string()), + TableIndexType::CHECKSUM256(value) => json!(value.as_string()), + TableIndexType::CHECKSUM160(value) => json!(value.as_string()), + } + } + + pub fn get_key_type(&self) -> Value { + match self { + TableIndexType::NAME(_) => Value::String("name".to_string()), + TableIndexType::UINT64(_) => Value::String("i64".to_string()), + TableIndexType::UINT128(_) => Value::String("i128".to_string()), + TableIndexType::FLOAT64(_) => Value::String("float64".to_string()), + TableIndexType::CHECKSUM256(_) => Value::String("sha256".to_string()), + TableIndexType::CHECKSUM160(_) => Value::String("ripemd160".to_string()), + } + } +} + #[derive(Debug, Serialize, Deserialize)] pub struct GetTableRowsParams { #[serde(deserialize_with = "deserialize_name")] @@ -326,13 +395,48 @@ pub struct GetTableRowsParams { impl GetTableRowsParams { pub fn to_json(&self) -> String { let mut req: HashMap<&str, Value> = HashMap::new(); - req.insert("json", Value::Bool(false)); req.insert("code", Value::String(self.code.to_string())); req.insert("table", Value::String(self.table.to_string())); let scope = self.scope.unwrap_or(self.code); req.insert("scope", Value::String(scope.to_string())); + req.insert("json", Value::Bool(false)); + + if let Some(limit) = &self.limit { + req.insert("limit", Value::String(limit.to_string())); + } + + if let Some(reverse) = &self.reverse { + req.insert("reverse", Value::Bool(*reverse)); + } + + if self.lower_bound.is_some() || self.upper_bound.is_some() { + if self.upper_bound.is_none() { + let lower = self.lower_bound.as_ref().unwrap(); + req.insert("key_type", lower.get_key_type()); + req.insert("lower_bound", lower.to_json()); + } else if self.lower_bound.is_none() { + let upper = self.upper_bound.as_ref().unwrap(); + req.insert("key_type", upper.get_key_type()); + req.insert("upper_bound", upper.to_json()); + } else { + let lower = self.lower_bound.as_ref().unwrap(); + let upper = self.upper_bound.as_ref().unwrap(); + if discriminant(lower) != discriminant(upper) { + panic!("lower_bound and upper_bound must be of the same type"); + } + req.insert("key_type", lower.get_key_type()); + req.insert("lower_bound", lower.to_json()); + req.insert("upper_bound", upper.to_json()); + } + + if let Some(index_position) = &self.index_position { + req.insert("index_position", index_position.to_json()); + } + + } + json!(req).to_string() } } diff --git a/crates/antelope/src/chain/checksum.rs b/crates/antelope/src/chain/checksum.rs index 27cf12e..16e82bc 100644 --- a/crates/antelope/src/chain/checksum.rs +++ b/crates/antelope/src/chain/checksum.rs @@ -135,6 +135,23 @@ impl Checksum256 { pub fn as_string(&self) -> String { bytes_to_hex(&self.data.to_vec()) } + + pub fn to_index(&self) -> String { + assert_eq!(self.data.len(), 32); + + let (first_16, second_16) = self.data.split_at(16); + + let mut first_reversed = first_16.to_vec(); + first_reversed.reverse(); + + let mut second_reversed = second_16.to_vec(); + second_reversed.reverse(); + + let mut new_vec = second_reversed; + new_vec.extend(first_reversed); + + bytes_to_hex(&new_vec) + } } impl Display for Checksum256 { diff --git a/crates/antelope/src/chain/time.rs b/crates/antelope/src/chain/time.rs index 001558c..19a263a 100644 --- a/crates/antelope/src/chain/time.rs +++ b/crates/antelope/src/chain/time.rs @@ -1,6 +1,7 @@ use chrono::{NaiveDateTime, TimeZone, Utc}; use serde::{de, Deserialize, Deserializer, Serialize}; use std::fmt; +use std::str::FromStr; use crate::chain::{Encoder, Packer}; @@ -10,6 +11,14 @@ pub struct TimePoint { pub elapsed: u64, } +impl FromStr for TimePoint { + type Err = String; + + fn from_str(s: &str) -> Result { + TimePoint::from_timestamp(s) + } +} + impl TimePoint { pub fn from_timestamp(t: &str) -> Result { //2023-12-16T16:17:47.500 diff --git a/crates/antelope/tests/client.rs b/crates/antelope/tests/client.rs index 5adfff2..1be1854 100644 --- a/crates/antelope/tests/client.rs +++ b/crates/antelope/tests/client.rs @@ -1,4 +1,4 @@ -use antelope::api::v1::structs::ErrorResponse; +use antelope::api::v1::structs::{ErrorResponse, IndexPosition, TableIndexType}; use antelope::{ api::{ client::APIClient, @@ -9,6 +9,8 @@ use antelope::{ serializer::{Decoder, Encoder, Packer}, StructPacker, }; +use antelope::api::client::DefaultProvider; +use antelope::util::bytes_to_hex; mod utils; use utils::mock_provider::MockProvider; @@ -191,7 +193,7 @@ pub async fn chain_get_abi() { // Check tables parsing assert_eq!(abi_object.abi.tables.len(), 2); - assert_eq!(abi_object.abi.tables[0].name, "accounts"); + assert_eq!(abi_object.abi.tables[0].name, name!("accounts")); } #[test] @@ -365,3 +367,79 @@ pub async fn chain_get_table_rows() { // assert.equal(String(res2.next_key), 'boidservices') // assert.equal(Number(res2.rows[1].balance).toFixed(6), (0.02566).toFixed(6)) } + + + +#[tokio::test] +pub async fn secondary_index() { + #[derive(Clone, Eq, PartialEq, Default, Debug, StructPacker)] + pub struct Proof { + proof_id: u64, + proof_digest: Checksum256, + proof_input: Vec, + } + + let mock_provider = MockProvider {}; + //let client = APIClient::custom_provider(mock_provider).unwrap(); + let mut client = APIClient::::default_provider_debug(String::from("https://testnet.telos.caleos.io"), true).unwrap(); + let checksum = Checksum256::from_hex("dc3264876b721aac60fe7270684c58bcd7e2c9e98ccdfdf4ed960a70b94fad32").unwrap(); + + let res1 = client + .v1_chain + .get_table_rows::(GetTableRowsParams { + code: name!("snarktor1234"), + table: name!("proofs"), + scope: Some(name!("snarktor1234")), + lower_bound: Some(TableIndexType::CHECKSUM256(checksum)), + // upper_bound: Some(TableIndexType::CHECKSUM256(checksum)), + upper_bound: None, + limit: Some(1), + reverse: None, + index_position: Some(IndexPosition::SECONDARY), + show_payer: None, + }) + .await + .unwrap(); + + + // "cbcbbc9c75ab9df67dbf6809a57396769c7d38bf922346c908726016bbc28069" + // "c8b2bb18bf9e660d4dbe02ffd63a99e1787ad39e805f80454875818b810b4dad" + // "0d53b3c0bc34ffefe4f605530fab2d4f567b894fe957034ac2361c63dabf82d1" + // "4d4977421255f8b6dda4ffed6e670a83500bcc1142c37178772f9af0fb68df0a" + // "506b98e490dd92c93d35e547cbe1b861e5d3366a5c52ca7cfaa121fb5276c8e4" + // "dc3264876b721aac60fe7270684c58bcd7e2c9e98ccdfdf4ed960a70b94fad32" + // Found matching proof_digest + // "2990ffdefe1c38333989136ce3695177b2aaf768bb65f96b9313c0336143bee5" + // "47a1888757221af3ccf8c1aba67672e1c3cfd68b9f6bd7866641a55335cb439a" + // "d9186878687748c3e01516a5b276773ee0760a321ad8e527ce6dc2b08c4cd73e" + // "f20cbe860c8879f085dfadae11b2b99cbaaa809668cec5d4d3fc714dc60a65d2" + // "61162de1db80bfae857545c4355422f7874a977d1191abfb802de6ef5b6b264d" + // "34a01ef58a3073c6093aac47bc209678bf9a3eadf15d15d90bca57df5ab71fd9" + // "95b7ab0f79df0aefa00530aedbba5ab0983babe2e24d11b811041dfc26060021" + + // let res1 = client + // .v1_chain + // .get_table_rows::(GetTableRowsParams { + // code: name!("snarktor1234"), + // table: name!("proofs"), + // scope: Some(name!("snarktor1234")), + // lower_bound: None, + // upper_bound: None, + // limit: Some(100), + // reverse: None, + // index_position: None, + // show_payer: None, + // }) + // .await + // .unwrap(); + + for row in res1.rows.iter() { + println!("{:?}", row.proof_digest.as_string()); + if row.proof_digest.as_string() == checksum.as_string() { + println!("Found matching proof_digest"); + } + } + + assert_eq!(res1.rows.len(), 1, "Should get exactly 1 row back"); + assert_eq!(res1.rows[0].proof_digest.as_string(), checksum.as_string(), "Should get back the matching proof_digest"); +} diff --git a/crates/antelope/tests/utils/mock_provider.rs b/crates/antelope/tests/utils/mock_provider.rs index affd7f0..3642757 100644 --- a/crates/antelope/tests/utils/mock_provider.rs +++ b/crates/antelope/tests/utils/mock_provider.rs @@ -53,6 +53,10 @@ impl Debug for MockProvider { #[async_trait::async_trait] impl Provider for MockProvider { + fn set_debug(&mut self, debug: bool) { + // TODO: Implement if we want debugging of the mock response in tests + } + async fn post(&self, path: String, body: Option) -> Result { self.call(HTTPMethod::POST, path, body) } From 6977b8bc126e5fac75c6305f81889a573a3d3a73 Mon Sep 17 00:00:00 2001 From: Jesse Schulman Date: Tue, 2 Jul 2024 21:06:09 -0700 Subject: [PATCH 05/26] Switch endian order for Checksum256 index, only works for rscdk compiled contracts --- crates/antelope/src/api/v1/structs.rs | 2 +- crates/antelope/src/chain/checksum.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/antelope/src/api/v1/structs.rs b/crates/antelope/src/api/v1/structs.rs index 60ebe71..6fc14de 100644 --- a/crates/antelope/src/api/v1/structs.rs +++ b/crates/antelope/src/api/v1/structs.rs @@ -359,7 +359,7 @@ impl TableIndexType { TableIndexType::UINT64(value) => json!(value.to_string()), TableIndexType::UINT128(value) => json!(value.to_string()), TableIndexType::FLOAT64(value) => json!(value.to_string()), - TableIndexType::CHECKSUM256(value) => json!(value.as_string()), + TableIndexType::CHECKSUM256(value) => json!(value.to_index()), TableIndexType::CHECKSUM160(value) => json!(value.as_string()), } } diff --git a/crates/antelope/src/chain/checksum.rs b/crates/antelope/src/chain/checksum.rs index 16e82bc..5182003 100644 --- a/crates/antelope/src/chain/checksum.rs +++ b/crates/antelope/src/chain/checksum.rs @@ -147,8 +147,8 @@ impl Checksum256 { let mut second_reversed = second_16.to_vec(); second_reversed.reverse(); - let mut new_vec = second_reversed; - new_vec.extend(first_reversed); + let mut new_vec = first_reversed; + new_vec.extend(second_reversed); bytes_to_hex(&new_vec) } From b8e104e783a9c1df079f50f0a88da86ce9f909fa Mon Sep 17 00:00:00 2001 From: Guillermo Rodriguez Date: Fri, 12 Jul 2024 15:32:02 -0300 Subject: [PATCH 06/26] Some changes to deseralize blocks --- crates/antelope/src/api/v1/chain.rs | 3 ++- crates/antelope/src/api/v1/structs.rs | 11 ++++++++++- crates/antelope/src/chain/signature.rs | 27 +++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/crates/antelope/src/api/v1/chain.rs b/crates/antelope/src/api/v1/chain.rs index 784d704..bf32752 100644 --- a/crates/antelope/src/api/v1/chain.rs +++ b/crates/antelope/src/api/v1/chain.rs @@ -124,8 +124,9 @@ impl ChainAPI { Ok(response) => { match serde_json::from_str::(&response) { Ok(block_response) => Ok(block_response), - Err(_) => { + Err(_serr) => { // Attempt to parse the error response + // println!("{:#?}", _serr); match serde_json::from_str::(&response) { Ok(error_response) => Err(ClientError::SERVER(ServerError { error: error_response, diff --git a/crates/antelope/src/api/v1/structs.rs b/crates/antelope/src/api/v1/structs.rs index 6fc14de..837a4e1 100644 --- a/crates/antelope/src/api/v1/structs.rs +++ b/crates/antelope/src/api/v1/structs.rs @@ -16,6 +16,7 @@ use crate::chain::{ authority::Authority, block_id::{deserialize_block_id, deserialize_optional_block_id, BlockId}, checksum::{deserialize_checksum256, Checksum160, Checksum256}, + signature::deserialize_signature, name::{deserialize_name, deserialize_optional_name, deserialize_vec_name, Name}, time::{deserialize_optional_timepoint, deserialize_timepoint, TimePoint, TimePointSec}, transaction::TransactionHeader, @@ -670,19 +671,27 @@ pub struct ABIResponse { #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] pub struct GetBlockResponse { + #[serde(rename = "timestamp")] + #[serde(deserialize_with = "deserialize_timepoint")] pub time_point: TimePoint, + #[serde(deserialize_with = "deserialize_name")] pub producer: Name, pub confirmed: u16, - pub pevious: BlockId, + #[serde(deserialize_with = "deserialize_block_id")] + pub previous: BlockId, + #[serde(deserialize_with = "deserialize_checksum256")] pub transaction_mroot: Checksum256, + #[serde(deserialize_with = "deserialize_checksum256")] pub action_mroot: Checksum256, pub schedule_version: u32, pub new_producers: Option, pub header_extensions: Option, // pub new_protocol_features: any, + #[serde(deserialize_with = "deserialize_signature")] pub producer_signature: Signature, pub transactions: Vec, pub block_extensions: Option>, + #[serde(deserialize_with = "deserialize_block_id")] pub id: BlockId, pub block_num: u32, pub ref_block_prefix: u32, diff --git a/crates/antelope/src/chain/signature.rs b/crates/antelope/src/chain/signature.rs index 8c2d887..c41c80b 100644 --- a/crates/antelope/src/chain/signature.rs +++ b/crates/antelope/src/chain/signature.rs @@ -1,9 +1,10 @@ +use core::fmt; use std::fmt::{Display, Formatter}; use ecdsa::RecoveryId; use k256::Secp256k1; use p256::NistP256; -use serde::{Deserialize, Serialize}; +use serde::{de::{self, Visitor}, Deserialize, Deserializer, Serialize}; use crate::{ base58, @@ -148,6 +149,30 @@ impl Signature { } } +pub(crate) fn deserialize_signature<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + struct SignatureVisitor; + + impl<'de> Visitor<'de> for SignatureVisitor { + type Value = Signature; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a hex string of length 64 (for 32 bytes)") + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + Signature::from_string(value).map_err(E::custom) + } + } + + deserializer.deserialize_str(SignatureVisitor) +} + impl Display for Signature { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.as_string()) From 57fbdb7b982e87b4914124019f675747256945a8 Mon Sep 17 00:00:00 2001 From: Guillermo Rodriguez Date: Wed, 31 Jul 2024 12:55:32 -0300 Subject: [PATCH 07/26] Disable TrxVarient on get block response for now --- crates/antelope/src/api/v1/structs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/antelope/src/api/v1/structs.rs b/crates/antelope/src/api/v1/structs.rs index 837a4e1..15abc6d 100644 --- a/crates/antelope/src/api/v1/structs.rs +++ b/crates/antelope/src/api/v1/structs.rs @@ -716,7 +716,7 @@ pub struct HeaderExtension { #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] pub struct GetBlockResponseTransactionReceipt { - pub trx: TrxVariant, //TODO: Implement TxVarient + pub trx: String, //TODO: Implement TxVarient } #[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] From a1ad141b22aff21f49d7f448d6c79b9b932977f5 Mon Sep 17 00:00:00 2001 From: Guillermo Rodriguez Date: Thu, 1 Aug 2024 20:26:30 -0300 Subject: [PATCH 08/26] Fix mock provider data --- ...937efb4.json => 4d87765f99207bb3d9d4d6c2f5ba1434742c358e.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename crates/antelope/tests/utils/mock_provider_data/{edfc4400e21d07b4add7e80d4fe253233937efb4.json => 4d87765f99207bb3d9d4d6c2f5ba1434742c358e.json} (100%) diff --git a/crates/antelope/tests/utils/mock_provider_data/edfc4400e21d07b4add7e80d4fe253233937efb4.json b/crates/antelope/tests/utils/mock_provider_data/4d87765f99207bb3d9d4d6c2f5ba1434742c358e.json similarity index 100% rename from crates/antelope/tests/utils/mock_provider_data/edfc4400e21d07b4add7e80d4fe253233937efb4.json rename to crates/antelope/tests/utils/mock_provider_data/4d87765f99207bb3d9d4d6c2f5ba1434742c358e.json From c8d60b2f465f53c0245b615e6f76070755a8a587 Mon Sep 17 00:00:00 2001 From: Guillermo Rodriguez Date: Thu, 1 Aug 2024 20:29:01 -0300 Subject: [PATCH 09/26] formatter and clippy pass --- crates/antelope/src/api/client.rs | 9 +++++--- crates/antelope/src/api/default_provider.rs | 4 ++-- crates/antelope/src/api/system/mod.rs | 2 +- crates/antelope/src/api/v1/chain.rs | 24 +++++++++++++++------ crates/antelope/src/api/v1/structs.rs | 8 +++---- crates/antelope/src/chain/signature.rs | 5 ++++- crates/antelope/src/serializer/packer.rs | 19 ++++++---------- crates/antelope/tests/client.rs | 22 ++++++++++++------- crates/antelope/tests/serializer.rs | 2 +- crates/macros/lib.rs | 2 +- 10 files changed, 57 insertions(+), 40 deletions(-) diff --git a/crates/antelope/src/api/client.rs b/crates/antelope/src/api/client.rs index ce16993..4e1574d 100644 --- a/crates/antelope/src/api/client.rs +++ b/crates/antelope/src/api/client.rs @@ -43,11 +43,14 @@ impl APIClient

{ pub fn default_provider(base_url: String) -> Result, String> { Self::default_provider_debug(base_url, false) } - - pub fn default_provider_debug(base_url: String, debug: bool) -> Result, String> { + + pub fn default_provider_debug( + base_url: String, + debug: bool, + ) -> Result, String> { let mut provider = DefaultProvider::new(base_url).unwrap(); provider.set_debug(debug); - + APIClient::custom_provider(provider) } diff --git a/crates/antelope/src/api/default_provider.rs b/crates/antelope/src/api/default_provider.rs index c292b2c..6cc4a1c 100644 --- a/crates/antelope/src/api/default_provider.rs +++ b/crates/antelope/src/api/default_provider.rs @@ -84,7 +84,7 @@ impl Provider for DefaultProvider { if self.debug { println!("Error: {}", err_str); } - + return Err(err_str); } @@ -92,7 +92,7 @@ impl Provider for DefaultProvider { if self.debug { println!("Response: {}", response); } - + Ok(response) } diff --git a/crates/antelope/src/api/system/mod.rs b/crates/antelope/src/api/system/mod.rs index 72e0482..3eaed89 100644 --- a/crates/antelope/src/api/system/mod.rs +++ b/crates/antelope/src/api/system/mod.rs @@ -1,6 +1,5 @@ pub mod structs; -use std::path::Path; use crate::api::client::{APIClient, Provider}; use crate::api::system::structs::{ CreateAccountParams, DelegateBandwidthAction, NewAccountAction, SetAbiAction, SetCodeAction, @@ -15,6 +14,7 @@ use crate::chain::private_key::PrivateKey; use crate::name; use crate::serializer::Encoder; use sha2::{Digest, Sha256}; +use std::path::Path; #[derive(Debug, Default, Clone)] pub struct SystemAPI { diff --git a/crates/antelope/src/api/v1/chain.rs b/crates/antelope/src/api/v1/chain.rs index bf32752..ec98cf3 100644 --- a/crates/antelope/src/api/v1/chain.rs +++ b/crates/antelope/src/api/v1/chain.rs @@ -2,7 +2,10 @@ use std::fmt::Debug; use serde_json::{self, Value}; -use crate::api::v1::structs::{ABIResponse, EncodingError, GetBlockResponse, GetTransactionStatusResponse, ServerError}; +use crate::api::v1::structs::{ + ABIResponse, EncodingError, GetBlockResponse, GetTransactionStatusResponse, ServerError, +}; +use crate::chain::checksum::{Checksum160, Checksum256}; use crate::{ api::{ client::Provider, @@ -21,7 +24,6 @@ use crate::{ serializer::formatter::{JSONObject, ValueTo}, util::hex_to_bytes, }; -use crate::chain::checksum::{Checksum160, Checksum256}; #[derive(Debug, Default, Clone)] pub struct ChainAPI { @@ -191,14 +193,20 @@ impl ChainAPI { } } - pub async fn get_transaction_status(&self, trx_id: Checksum256) -> Result> { + pub async fn get_transaction_status( + &self, + trx_id: Checksum256, + ) -> Result> { let payload = serde_json::json!({ "id": trx_id, }); let result = self .provider - .post(String::from("/v1/chain/get_transaction_status"), Some(payload.to_string())) + .post( + String::from("/v1/chain/get_transaction_status"), + Some(payload.to_string()), + ) .await; match result { @@ -264,10 +272,14 @@ impl ChainAPI { next_key = Some(TableIndexType::UINT128(next_key_str.parse().unwrap())); } Some(TableIndexType::CHECKSUM160(_)) => { - next_key = Some(TableIndexType::CHECKSUM160(Checksum160::from_bytes(hex_to_bytes(&next_key_str).as_slice()).unwrap())); + next_key = Some(TableIndexType::CHECKSUM160( + Checksum160::from_bytes(hex_to_bytes(&next_key_str).as_slice()).unwrap(), + )); } Some(TableIndexType::CHECKSUM256(_)) => { - next_key = Some(TableIndexType::CHECKSUM256(Checksum256::from_bytes(hex_to_bytes(&next_key_str).as_slice()).unwrap())); + next_key = Some(TableIndexType::CHECKSUM256( + Checksum256::from_bytes(hex_to_bytes(&next_key_str).as_slice()).unwrap(), + )); } Some(TableIndexType::FLOAT64(_)) => { next_key = Some(TableIndexType::FLOAT64(next_key_str.parse().unwrap())); diff --git a/crates/antelope/src/api/v1/structs.rs b/crates/antelope/src/api/v1/structs.rs index 15abc6d..0b44230 100644 --- a/crates/antelope/src/api/v1/structs.rs +++ b/crates/antelope/src/api/v1/structs.rs @@ -5,7 +5,6 @@ use serde::{Deserialize, Deserializer, Serialize}; use serde_json::{json, Value}; use std::fmt; use std::mem::discriminant; -use digest::block_buffer::Block; use crate::chain::abi::ABI; use crate::chain::public_key::PublicKey; @@ -16,8 +15,8 @@ use crate::chain::{ authority::Authority, block_id::{deserialize_block_id, deserialize_optional_block_id, BlockId}, checksum::{deserialize_checksum256, Checksum160, Checksum256}, - signature::deserialize_signature, name::{deserialize_name, deserialize_optional_name, deserialize_vec_name, Name}, + signature::deserialize_signature, time::{deserialize_optional_timepoint, deserialize_timepoint, TimePoint, TimePointSec}, transaction::TransactionHeader, varint::VarUint32, @@ -364,7 +363,7 @@ impl TableIndexType { TableIndexType::CHECKSUM160(value) => json!(value.as_string()), } } - + pub fn get_key_type(&self) -> Value { match self { TableIndexType::NAME(_) => Value::String("name".to_string()), @@ -411,7 +410,7 @@ impl GetTableRowsParams { if let Some(reverse) = &self.reverse { req.insert("reverse", Value::Bool(*reverse)); } - + if self.lower_bound.is_some() || self.upper_bound.is_some() { if self.upper_bound.is_none() { let lower = self.lower_bound.as_ref().unwrap(); @@ -435,7 +434,6 @@ impl GetTableRowsParams { if let Some(index_position) = &self.index_position { req.insert("index_position", index_position.to_json()); } - } json!(req).to_string() diff --git a/crates/antelope/src/chain/signature.rs b/crates/antelope/src/chain/signature.rs index c41c80b..d46e770 100644 --- a/crates/antelope/src/chain/signature.rs +++ b/crates/antelope/src/chain/signature.rs @@ -4,7 +4,10 @@ use std::fmt::{Display, Formatter}; use ecdsa::RecoveryId; use k256::Secp256k1; use p256::NistP256; -use serde::{de::{self, Visitor}, Deserialize, Deserializer, Serialize}; +use serde::{ + de::{self, Visitor}, + Deserialize, Deserializer, Serialize, +}; use crate::{ base58, diff --git a/crates/antelope/src/serializer/packer.rs b/crates/antelope/src/serializer/packer.rs index a2a3d55..31f848a 100644 --- a/crates/antelope/src/serializer/packer.rs +++ b/crates/antelope/src/serializer/packer.rs @@ -299,27 +299,22 @@ impl_packed!(f64); #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug, Default)] pub struct Float128 { - /// pub data: [u8; 16], } impl Float128 { - /// - pub fn new(data: [u8;16]) -> Self { - Self { - data: data - } + pub fn new(data: [u8; 16]) -> Self { + Self { data } } - /// pub fn data(&self) -> &[u8; 16] { - return &self.data; + &self.data } } impl Packer for Float128 { fn size(&self) -> usize { - return 16; + 16 } fn pack(&self, enc: &mut Encoder) -> usize { @@ -332,7 +327,7 @@ impl Packer for Float128 { let size = self.size(); assert!(raw.len() >= size, "Float128.unpack: buffer overflow!"); slice_copy(&mut self.data, &raw[..size]); - return self.size(); + self.size() } } @@ -470,8 +465,8 @@ where /// Implement `Packer` for `Box` type. impl Packer for Box - where - T: Packer + Default, +where + T: Packer + Default, { /// Returns the size of this value in bytes. fn size(&self) -> usize { diff --git a/crates/antelope/tests/client.rs b/crates/antelope/tests/client.rs index 1be1854..c7575f7 100644 --- a/crates/antelope/tests/client.rs +++ b/crates/antelope/tests/client.rs @@ -1,3 +1,4 @@ +use antelope::api::client::DefaultProvider; use antelope::api::v1::structs::{ErrorResponse, IndexPosition, TableIndexType}; use antelope::{ api::{ @@ -9,8 +10,6 @@ use antelope::{ serializer::{Decoder, Encoder, Packer}, StructPacker, }; -use antelope::api::client::DefaultProvider; -use antelope::util::bytes_to_hex; mod utils; use utils::mock_provider::MockProvider; @@ -368,8 +367,6 @@ pub async fn chain_get_table_rows() { // assert.equal(Number(res2.rows[1].balance).toFixed(6), (0.02566).toFixed(6)) } - - #[tokio::test] pub async fn secondary_index() { #[derive(Clone, Eq, PartialEq, Default, Debug, StructPacker)] @@ -381,8 +378,14 @@ pub async fn secondary_index() { let mock_provider = MockProvider {}; //let client = APIClient::custom_provider(mock_provider).unwrap(); - let mut client = APIClient::::default_provider_debug(String::from("https://testnet.telos.caleos.io"), true).unwrap(); - let checksum = Checksum256::from_hex("dc3264876b721aac60fe7270684c58bcd7e2c9e98ccdfdf4ed960a70b94fad32").unwrap(); + let client = APIClient::::default_provider_debug( + String::from("https://testnet.telos.caleos.io"), + true, + ) + .unwrap(); + let checksum = + Checksum256::from_hex("dc3264876b721aac60fe7270684c58bcd7e2c9e98ccdfdf4ed960a70b94fad32") + .unwrap(); let res1 = client .v1_chain @@ -401,7 +404,6 @@ pub async fn secondary_index() { .await .unwrap(); - // "cbcbbc9c75ab9df67dbf6809a57396769c7d38bf922346c908726016bbc28069" // "c8b2bb18bf9e660d4dbe02ffd63a99e1787ad39e805f80454875818b810b4dad" // "0d53b3c0bc34ffefe4f605530fab2d4f567b894fe957034ac2361c63dabf82d1" @@ -441,5 +443,9 @@ pub async fn secondary_index() { } assert_eq!(res1.rows.len(), 1, "Should get exactly 1 row back"); - assert_eq!(res1.rows[0].proof_digest.as_string(), checksum.as_string(), "Should get back the matching proof_digest"); + assert_eq!( + res1.rows[0].proof_digest.as_string(), + checksum.as_string(), + "Should get back the matching proof_digest" + ); } diff --git a/crates/antelope/tests/serializer.rs b/crates/antelope/tests/serializer.rs index 2981f39..3747cc3 100644 --- a/crates/antelope/tests/serializer.rs +++ b/crates/antelope/tests/serializer.rs @@ -476,7 +476,7 @@ fn variant() { MyVariant::StructOption(opt) => { assert!(opt.is_some(), "Option should be Some"); let my_struct = opt.as_ref().unwrap(); - assert_eq!(my_struct.field1, true); + assert!(my_struct.field1); } _ => { panic!("Expected MyUint8"); diff --git a/crates/macros/lib.rs b/crates/macros/lib.rs index 2ed506e..89ca12b 100644 --- a/crates/macros/lib.rs +++ b/crates/macros/lib.rs @@ -73,7 +73,7 @@ pub fn enum_packer_macro(input: TokenStream) -> TokenStream { let gen = match input.data { syn::Data::Enum(data_enum) => { - let size_variants = data_enum.variants.iter().enumerate().map(|(_i, variant)| { + let size_variants = data_enum.variants.iter().map(|variant| { let variant_ident = &variant.ident; match &variant.fields { Fields::Unnamed(fields) => { From 02d0e7e723c655d1103e4863af86eabfd4f1d69f Mon Sep 17 00:00:00 2001 From: Paolo Tagliaferri Date: Tue, 10 Sep 2024 18:32:54 +0200 Subject: [PATCH 10/26] Partially revert "Switch endian order for Checksum256 index, only works for rscdk compiled contracts" This reverts commit 6977b8bc126e5fac75c6305f81889a573a3d3a73, in particular the endianness of Checksum256. This is needed to be compatible with the C++ smart contracts compiler, while rscdk (Rust WASM compiler) needs the commit that here is being reverted. This means that going on antelope-rs will be compatible with the C++ smart contracts compiler and not with the Rust compiler. --- crates/antelope/src/chain/checksum.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/antelope/src/chain/checksum.rs b/crates/antelope/src/chain/checksum.rs index 5182003..16e82bc 100644 --- a/crates/antelope/src/chain/checksum.rs +++ b/crates/antelope/src/chain/checksum.rs @@ -147,8 +147,8 @@ impl Checksum256 { let mut second_reversed = second_16.to_vec(); second_reversed.reverse(); - let mut new_vec = first_reversed; - new_vec.extend(second_reversed); + let mut new_vec = second_reversed; + new_vec.extend(first_reversed); bytes_to_hex(&new_vec) } From 598dd548e55ab175fc61ba9476666baaa592b0fc Mon Sep 17 00:00:00 2001 From: Paolo Tagliaferri Date: Wed, 11 Sep 2024 08:03:36 +0200 Subject: [PATCH 11/26] Removed `secondary_index` test The test was meant to check the consistency of the Checksum256 encoding with the SNARKtor contracts and the WASM-compiled smart contracts in general. However, given that the `rscdk` compiler treats the encoding of Checksum256 with a different encoding compared to the C++ compiler, the test has been removed. It could be restored once the `rscdk` issue is fixed. --- crates/antelope/tests/client.rs | 83 --------------------------------- 1 file changed, 83 deletions(-) diff --git a/crates/antelope/tests/client.rs b/crates/antelope/tests/client.rs index c7575f7..46f71cd 100644 --- a/crates/antelope/tests/client.rs +++ b/crates/antelope/tests/client.rs @@ -366,86 +366,3 @@ pub async fn chain_get_table_rows() { // assert.equal(String(res2.next_key), 'boidservices') // assert.equal(Number(res2.rows[1].balance).toFixed(6), (0.02566).toFixed(6)) } - -#[tokio::test] -pub async fn secondary_index() { - #[derive(Clone, Eq, PartialEq, Default, Debug, StructPacker)] - pub struct Proof { - proof_id: u64, - proof_digest: Checksum256, - proof_input: Vec, - } - - let mock_provider = MockProvider {}; - //let client = APIClient::custom_provider(mock_provider).unwrap(); - let client = APIClient::::default_provider_debug( - String::from("https://testnet.telos.caleos.io"), - true, - ) - .unwrap(); - let checksum = - Checksum256::from_hex("dc3264876b721aac60fe7270684c58bcd7e2c9e98ccdfdf4ed960a70b94fad32") - .unwrap(); - - let res1 = client - .v1_chain - .get_table_rows::(GetTableRowsParams { - code: name!("snarktor1234"), - table: name!("proofs"), - scope: Some(name!("snarktor1234")), - lower_bound: Some(TableIndexType::CHECKSUM256(checksum)), - // upper_bound: Some(TableIndexType::CHECKSUM256(checksum)), - upper_bound: None, - limit: Some(1), - reverse: None, - index_position: Some(IndexPosition::SECONDARY), - show_payer: None, - }) - .await - .unwrap(); - - // "cbcbbc9c75ab9df67dbf6809a57396769c7d38bf922346c908726016bbc28069" - // "c8b2bb18bf9e660d4dbe02ffd63a99e1787ad39e805f80454875818b810b4dad" - // "0d53b3c0bc34ffefe4f605530fab2d4f567b894fe957034ac2361c63dabf82d1" - // "4d4977421255f8b6dda4ffed6e670a83500bcc1142c37178772f9af0fb68df0a" - // "506b98e490dd92c93d35e547cbe1b861e5d3366a5c52ca7cfaa121fb5276c8e4" - // "dc3264876b721aac60fe7270684c58bcd7e2c9e98ccdfdf4ed960a70b94fad32" - // Found matching proof_digest - // "2990ffdefe1c38333989136ce3695177b2aaf768bb65f96b9313c0336143bee5" - // "47a1888757221af3ccf8c1aba67672e1c3cfd68b9f6bd7866641a55335cb439a" - // "d9186878687748c3e01516a5b276773ee0760a321ad8e527ce6dc2b08c4cd73e" - // "f20cbe860c8879f085dfadae11b2b99cbaaa809668cec5d4d3fc714dc60a65d2" - // "61162de1db80bfae857545c4355422f7874a977d1191abfb802de6ef5b6b264d" - // "34a01ef58a3073c6093aac47bc209678bf9a3eadf15d15d90bca57df5ab71fd9" - // "95b7ab0f79df0aefa00530aedbba5ab0983babe2e24d11b811041dfc26060021" - - // let res1 = client - // .v1_chain - // .get_table_rows::(GetTableRowsParams { - // code: name!("snarktor1234"), - // table: name!("proofs"), - // scope: Some(name!("snarktor1234")), - // lower_bound: None, - // upper_bound: None, - // limit: Some(100), - // reverse: None, - // index_position: None, - // show_payer: None, - // }) - // .await - // .unwrap(); - - for row in res1.rows.iter() { - println!("{:?}", row.proof_digest.as_string()); - if row.proof_digest.as_string() == checksum.as_string() { - println!("Found matching proof_digest"); - } - } - - assert_eq!(res1.rows.len(), 1, "Should get exactly 1 row back"); - assert_eq!( - res1.rows[0].proof_digest.as_string(), - checksum.as_string(), - "Should get back the matching proof_digest" - ); -} From feb151b28499946698c25c3411b574801cc869e6 Mon Sep 17 00:00:00 2001 From: Paolo Tagliaferri Date: Wed, 11 Sep 2024 10:26:02 +0200 Subject: [PATCH 12/26] Removed commented code --- crates/antelope/src/api/v1/chain.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/antelope/src/api/v1/chain.rs b/crates/antelope/src/api/v1/chain.rs index ec98cf3..242e752 100644 --- a/crates/antelope/src/api/v1/chain.rs +++ b/crates/antelope/src/api/v1/chain.rs @@ -128,7 +128,6 @@ impl ChainAPI { Ok(block_response) => Ok(block_response), Err(_serr) => { // Attempt to parse the error response - // println!("{:#?}", _serr); match serde_json::from_str::(&response) { Ok(error_response) => Err(ClientError::SERVER(ServerError { error: error_response, From 4c98aacd47f38805fd8a25ade541c31da56bc6d7 Mon Sep 17 00:00:00 2001 From: MarcoOl94 Date: Wed, 11 Sep 2024 17:58:29 +0200 Subject: [PATCH 13/26] Fixed get account json parsing --- crates/antelope/src/api/v1/structs.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crates/antelope/src/api/v1/structs.rs b/crates/antelope/src/api/v1/structs.rs index 0b44230..32675b6 100644 --- a/crates/antelope/src/api/v1/structs.rs +++ b/crates/antelope/src/api/v1/structs.rs @@ -529,7 +529,9 @@ pub struct AccountRexInfoMaturities { #[derive(Debug, Serialize, Deserialize)] pub struct AccountResourceLimit { used: i64, + #[serde(deserialize_with = "deserialize_i64_from_string_or_i64")] available: i64, + #[serde(deserialize_with = "deserialize_i64_from_string_or_i64")] max: i64, #[serde( deserialize_with = "deserialize_optional_timepoint", @@ -650,6 +652,7 @@ pub struct AccountVoterInfo { #[serde(deserialize_with = "deserialize_vec_name")] producers: Vec, staked: Option, + last_stake: Option, #[serde(deserialize_with = "deserialize_f64_from_string")] last_vote_weight: f64, #[serde(deserialize_with = "deserialize_f64_from_string")] @@ -946,3 +949,14 @@ where deserializer.deserialize_any(StringOrI64Visitor) } + + +// TODO: Fix it! +#[test] +fn test_deserialize() { + let test_string = "{\"account_name\":\"eosio\",\"head_block_num\":56,\"head_block_time\":\"2024-08-29T15:27:24.500\",\"privileged\":true,\"last_code_update\":\"2024-08-29T14:06:02.000\",\"created\":\"2019-08-07T12:00:00.000\",\"core_liquid_balance\":\"99986000.0000 TLOS\",\"ram_quota\":-1,\"net_weight\":-1,\"cpu_weight\":-1,\"net_limit\":{\"used\":-1,\"available\":-1,\"max\":-1,\"last_usage_update_time\":\"2024-08-29T15:27:25.000\",\"current_used\":-1},\"cpu_limit\":{\"used\":-1,\"available\":-1,\"max\":-1,\"last_usage_update_time\":\"2024-08-29T15:27:25.000\",\"current_used\":-1},\"ram_usage\":3485037,\"permissions\":[{\"perm_name\":\"active\",\"parent\":\"owner\",\"required_auth\":{\"threshold\":1,\"keys\":[{\"key\":\"EOS5uHeBsURAT6bBXNtvwKtWaiDSDJSdSmc96rHVws5M1qqVCkAm6\",\"weight\":1}],\"accounts\":[],\"waits\":[]},\"linked_actions\":[]},{\"perm_name\":\"owner\",\"parent\":\"\",\"required_auth\":{\"threshold\":1,\"keys\":[{\"key\":\"EOS5uHeBsURAT6bBXNtvwKtWaiDSDJSdSmc96rHVws5M1qqVCkAm6\",\"weight\":1}],\"accounts\":[],\"waits\":[]},\"linked_actions\":[]}],\"total_resources\":null,\"self_delegated_bandwidth\":null,\"refund_request\":null,\"voter_info\":null,\"rex_info\":null,\"subjective_cpu_bill_limit\":{\"used\":0,\"available\":0,\"max\":0,\"last_usage_update_time\":\"2000-01-01T00:00:00.000\",\"current_used\":0},\"eosio_any_linked_actions\":[]}"; + let test_string2 = "{\"account_name\":\"alice\",\"head_block_num\":56,\"head_block_time\":\"2024-08-29T15:27:24.500\",\"privileged\":false,\"last_code_update\":\"1970-01-01T00:00:00.000\",\"created\":\"2024-08-29T14:06:02.000\",\"core_liquid_balance\":\"100.0000 TLOS\",\"ram_quota\":610645714,\"net_weight\":10000000,\"cpu_weight\":10000000,\"net_limit\":{\"used\":0,\"available\":\"95719449600\",\"max\":\"95719449600\",\"last_usage_update_time\":\"2024-08-29T14:06:02.000\",\"current_used\":0},\"cpu_limit\":{\"used\":0,\"available\":\"364783305600\",\"max\":\"364783305600\",\"last_usage_update_time\":\"2024-08-29T14:06:02.000\",\"current_used\":0},\"ram_usage\":3566,\"permissions\":[{\"perm_name\":\"active\",\"parent\":\"owner\",\"required_auth\":{\"threshold\":1,\"keys\":[{\"key\":\"EOS77jzbmLuakAHpm2Q5ew8EL7Y7gGkfSzqJCmCNDDXWEsBP3xnDc\",\"weight\":1}],\"accounts\":[],\"waits\":[]},\"linked_actions\":[]},{\"perm_name\":\"owner\",\"parent\":\"\",\"required_auth\":{\"threshold\":1,\"keys\":[{\"key\":\"EOS77jzbmLuakAHpm2Q5ew8EL7Y7gGkfSzqJCmCNDDXWEsBP3xnDc\",\"weight\":1}],\"accounts\":[],\"waits\":[]},\"linked_actions\":[]}],\"total_resources\":{\"owner\":\"alice\",\"net_weight\":\"1000.0000 TLOS\",\"cpu_weight\":\"1000.0000 TLOS\",\"ram_bytes\":610644314},\"self_delegated_bandwidth\":{\"from\":\"alice\",\"to\":\"alice\",\"net_weight\":\"1000.0000 TLOS\",\"cpu_weight\":\"1000.0000 TLOS\"},\"refund_request\":null,\"voter_info\":{\"owner\":\"alice\",\"proxy\":\"\",\"producers\":[],\"staked\":20000000,\"last_stake\":0,\"last_vote_weight\":\"0.00000000000000000\",\"proxied_vote_weight\":\"0.00000000000000000\",\"is_proxy\":0,\"flags1\":0,\"reserved2\":0,\"reserved3\":\"0 \"},\"rex_info\":null,\"subjective_cpu_bill_limit\":{\"used\":0,\"available\":0,\"max\":0,\"last_usage_update_time\":\"2000-01-01T00:00:00.000\",\"current_used\":0},\"eosio_any_linked_actions\":[]}"; + let test_string3 = "{\"account_name\":\"alice\",\"head_block_num\":56,\"head_block_time\":\"2024-08-29T15:46:42.000\",\"privileged\":false,\"last_code_update\":\"1970-01-01T00:00:00.000\",\"created\":\"2024-08-29T14:06:02.000\",\"ram_quota\":610645714,\"net_weight\":10000000,\"cpu_weight\":10000000,\"net_limit\":{\"used\":0,\"available\":\"95719449600\",\"max\":\"95719449600\",\"last_usage_update_time\":\"2024-08-29T14:06:02.000\",\"current_used\":0},\"cpu_limit\":{\"used\":0,\"available\":\"364783305600\",\"max\":\"364783305600\",\"last_usage_update_time\":\"2024-08-29T14:06:02.000\",\"current_used\":0},\"ram_usage\":3566,\"permissions\":[{\"perm_name\":\"active\",\"parent\":\"owner\",\"required_auth\":{\"threshold\":1,\"keys\":[{\"key\":\"EOS77jzbmLuakAHpm2Q5ew8EL7Y7gGkfSzqJCmCNDDXWEsBP3xnDc\",\"weight\":1}],\"accounts\":[],\"waits\":[]},\"linked_actions\":[]},{\"perm_name\":\"owner\",\"parent\":\"\",\"required_auth\":{\"threshold\":1,\"keys\":[{\"key\":\"EOS77jzbmLuakAHpm2Q5ew8EL7Y7gGkfSzqJCmCNDDXWEsBP3xnDc\",\"weight\":1}],\"accounts\":[],\"waits\":[]},\"linked_actions\":[]}],\"total_resources\":{\"owner\":\"alice\",\"net_weight\":\"1000.0000 TLOS\",\"cpu_weight\":\"1000.0000 TLOS\",\"ram_bytes\":610644314},\"self_delegated_bandwidth\":{\"from\":\"alice\",\"to\":\"alice\",\"net_weight\":\"1000.0000 TLOS\",\"cpu_weight\":\"1000.0000 TLOS\"},\"refund_request\":null,\"voter_info\":{\"owner\":\"alice\",\"proxy\":\"\",\"producers\":[],\"staked\":20000000,\"last_stake\":0,\"last_vote_weight\":\"0.00000000000000000\",\"proxied_vote_weight\":\"0.00000000000000000\",\"is_proxy\":0,\"flags1\":0,\"reserved2\":0,\"reserved3\":\"0 \"},\"rex_info\":null,\"subjective_cpu_bill_limit\":{\"used\":0,\"available\":0,\"max\":0,\"last_usage_update_time\":\"2000-01-01T00:00:00.000\",\"current_used\":0},\"eosio_any_linked_actions\":[]}"; + let res = serde_json::from_str::(&test_string3).unwrap(); + println!("{:#?}", res); +} \ No newline at end of file From 7a4fc47590e9621affd7916ef1e124d7484ea722 Mon Sep 17 00:00:00 2001 From: Paolo Tagliaferri Date: Wed, 11 Sep 2024 17:58:29 +0200 Subject: [PATCH 14/26] Refactored v1/struct unit tests - Added the conditional configuration of tests - Split the account deserialization test into 3 smaller tests - Switched to raw strings to keep JSON formatting and make the content more readable --- crates/antelope/src/api/v1/structs.rs | 308 +++++++++++++++++++++++++- 1 file changed, 301 insertions(+), 7 deletions(-) diff --git a/crates/antelope/src/api/v1/structs.rs b/crates/antelope/src/api/v1/structs.rs index 32675b6..b6ab57b 100644 --- a/crates/antelope/src/api/v1/structs.rs +++ b/crates/antelope/src/api/v1/structs.rs @@ -950,13 +950,307 @@ where deserializer.deserialize_any(StringOrI64Visitor) } +#[cfg(test)] +mod tests { + use crate::api::v1::structs::AccountObject; -// TODO: Fix it! #[test] -fn test_deserialize() { - let test_string = "{\"account_name\":\"eosio\",\"head_block_num\":56,\"head_block_time\":\"2024-08-29T15:27:24.500\",\"privileged\":true,\"last_code_update\":\"2024-08-29T14:06:02.000\",\"created\":\"2019-08-07T12:00:00.000\",\"core_liquid_balance\":\"99986000.0000 TLOS\",\"ram_quota\":-1,\"net_weight\":-1,\"cpu_weight\":-1,\"net_limit\":{\"used\":-1,\"available\":-1,\"max\":-1,\"last_usage_update_time\":\"2024-08-29T15:27:25.000\",\"current_used\":-1},\"cpu_limit\":{\"used\":-1,\"available\":-1,\"max\":-1,\"last_usage_update_time\":\"2024-08-29T15:27:25.000\",\"current_used\":-1},\"ram_usage\":3485037,\"permissions\":[{\"perm_name\":\"active\",\"parent\":\"owner\",\"required_auth\":{\"threshold\":1,\"keys\":[{\"key\":\"EOS5uHeBsURAT6bBXNtvwKtWaiDSDJSdSmc96rHVws5M1qqVCkAm6\",\"weight\":1}],\"accounts\":[],\"waits\":[]},\"linked_actions\":[]},{\"perm_name\":\"owner\",\"parent\":\"\",\"required_auth\":{\"threshold\":1,\"keys\":[{\"key\":\"EOS5uHeBsURAT6bBXNtvwKtWaiDSDJSdSmc96rHVws5M1qqVCkAm6\",\"weight\":1}],\"accounts\":[],\"waits\":[]},\"linked_actions\":[]}],\"total_resources\":null,\"self_delegated_bandwidth\":null,\"refund_request\":null,\"voter_info\":null,\"rex_info\":null,\"subjective_cpu_bill_limit\":{\"used\":0,\"available\":0,\"max\":0,\"last_usage_update_time\":\"2000-01-01T00:00:00.000\",\"current_used\":0},\"eosio_any_linked_actions\":[]}"; - let test_string2 = "{\"account_name\":\"alice\",\"head_block_num\":56,\"head_block_time\":\"2024-08-29T15:27:24.500\",\"privileged\":false,\"last_code_update\":\"1970-01-01T00:00:00.000\",\"created\":\"2024-08-29T14:06:02.000\",\"core_liquid_balance\":\"100.0000 TLOS\",\"ram_quota\":610645714,\"net_weight\":10000000,\"cpu_weight\":10000000,\"net_limit\":{\"used\":0,\"available\":\"95719449600\",\"max\":\"95719449600\",\"last_usage_update_time\":\"2024-08-29T14:06:02.000\",\"current_used\":0},\"cpu_limit\":{\"used\":0,\"available\":\"364783305600\",\"max\":\"364783305600\",\"last_usage_update_time\":\"2024-08-29T14:06:02.000\",\"current_used\":0},\"ram_usage\":3566,\"permissions\":[{\"perm_name\":\"active\",\"parent\":\"owner\",\"required_auth\":{\"threshold\":1,\"keys\":[{\"key\":\"EOS77jzbmLuakAHpm2Q5ew8EL7Y7gGkfSzqJCmCNDDXWEsBP3xnDc\",\"weight\":1}],\"accounts\":[],\"waits\":[]},\"linked_actions\":[]},{\"perm_name\":\"owner\",\"parent\":\"\",\"required_auth\":{\"threshold\":1,\"keys\":[{\"key\":\"EOS77jzbmLuakAHpm2Q5ew8EL7Y7gGkfSzqJCmCNDDXWEsBP3xnDc\",\"weight\":1}],\"accounts\":[],\"waits\":[]},\"linked_actions\":[]}],\"total_resources\":{\"owner\":\"alice\",\"net_weight\":\"1000.0000 TLOS\",\"cpu_weight\":\"1000.0000 TLOS\",\"ram_bytes\":610644314},\"self_delegated_bandwidth\":{\"from\":\"alice\",\"to\":\"alice\",\"net_weight\":\"1000.0000 TLOS\",\"cpu_weight\":\"1000.0000 TLOS\"},\"refund_request\":null,\"voter_info\":{\"owner\":\"alice\",\"proxy\":\"\",\"producers\":[],\"staked\":20000000,\"last_stake\":0,\"last_vote_weight\":\"0.00000000000000000\",\"proxied_vote_weight\":\"0.00000000000000000\",\"is_proxy\":0,\"flags1\":0,\"reserved2\":0,\"reserved3\":\"0 \"},\"rex_info\":null,\"subjective_cpu_bill_limit\":{\"used\":0,\"available\":0,\"max\":0,\"last_usage_update_time\":\"2000-01-01T00:00:00.000\",\"current_used\":0},\"eosio_any_linked_actions\":[]}"; - let test_string3 = "{\"account_name\":\"alice\",\"head_block_num\":56,\"head_block_time\":\"2024-08-29T15:46:42.000\",\"privileged\":false,\"last_code_update\":\"1970-01-01T00:00:00.000\",\"created\":\"2024-08-29T14:06:02.000\",\"ram_quota\":610645714,\"net_weight\":10000000,\"cpu_weight\":10000000,\"net_limit\":{\"used\":0,\"available\":\"95719449600\",\"max\":\"95719449600\",\"last_usage_update_time\":\"2024-08-29T14:06:02.000\",\"current_used\":0},\"cpu_limit\":{\"used\":0,\"available\":\"364783305600\",\"max\":\"364783305600\",\"last_usage_update_time\":\"2024-08-29T14:06:02.000\",\"current_used\":0},\"ram_usage\":3566,\"permissions\":[{\"perm_name\":\"active\",\"parent\":\"owner\",\"required_auth\":{\"threshold\":1,\"keys\":[{\"key\":\"EOS77jzbmLuakAHpm2Q5ew8EL7Y7gGkfSzqJCmCNDDXWEsBP3xnDc\",\"weight\":1}],\"accounts\":[],\"waits\":[]},\"linked_actions\":[]},{\"perm_name\":\"owner\",\"parent\":\"\",\"required_auth\":{\"threshold\":1,\"keys\":[{\"key\":\"EOS77jzbmLuakAHpm2Q5ew8EL7Y7gGkfSzqJCmCNDDXWEsBP3xnDc\",\"weight\":1}],\"accounts\":[],\"waits\":[]},\"linked_actions\":[]}],\"total_resources\":{\"owner\":\"alice\",\"net_weight\":\"1000.0000 TLOS\",\"cpu_weight\":\"1000.0000 TLOS\",\"ram_bytes\":610644314},\"self_delegated_bandwidth\":{\"from\":\"alice\",\"to\":\"alice\",\"net_weight\":\"1000.0000 TLOS\",\"cpu_weight\":\"1000.0000 TLOS\"},\"refund_request\":null,\"voter_info\":{\"owner\":\"alice\",\"proxy\":\"\",\"producers\":[],\"staked\":20000000,\"last_stake\":0,\"last_vote_weight\":\"0.00000000000000000\",\"proxied_vote_weight\":\"0.00000000000000000\",\"is_proxy\":0,\"flags1\":0,\"reserved2\":0,\"reserved3\":\"0 \"},\"rex_info\":null,\"subjective_cpu_bill_limit\":{\"used\":0,\"available\":0,\"max\":0,\"last_usage_update_time\":\"2000-01-01T00:00:00.000\",\"current_used\":0},\"eosio_any_linked_actions\":[]}"; - let res = serde_json::from_str::(&test_string3).unwrap(); + fn deserialize_simple_account() { + // This simple account response doesn't contain details about `total_resources`, `self_delegated_bandwidth`, + // `refund_request`, `voter_info`, and `rex_info`. + // Such fields are null. + let simple_account_json = r#" + { + "account_name": "eosio", + "head_block_num": 56, + "head_block_time": "2024-08-29T15:27:24.500", + "privileged": true, + "last_code_update": "2024-08-29T14:06:02.000", + "created": "2019-08-07T12:00:00.000", + "core_liquid_balance": "99986000.0000 TLOS", + "ram_quota": -1, + "net_weight": -1, + "cpu_weight": -1, + "net_limit": { + "used": -1, + "available": -1, + "max": -1, + "last_usage_update_time": "2024-08-29T15:27:25.000", + "current_used": -1 + }, + "cpu_limit": { + "used": -1, + "available": -1, + "max": -1, + "last_usage_update_time": "2024-08-29T15:27:25.000", + "current_used": -1 + }, + "ram_usage": 3485037, + "permissions": [ + { + "perm_name": "active", + "parent": "owner", + "required_auth": { + "threshold": 1, + "keys": [ + { + "key": "EOS5uHeBsURAT6bBXNtvwKtWaiDSDJSdSmc96rHVws5M1qqVCkAm6", + "weight": 1 + } + ], + "accounts": [], + "waits": [] + }, + "linked_actions": [] + }, + { + "perm_name": "owner", + "parent": "", + "required_auth": { + "threshold": 1, + "keys": [ + { + "key": "EOS5uHeBsURAT6bBXNtvwKtWaiDSDJSdSmc96rHVws5M1qqVCkAm6", + "weight": 1 + } + ], + "accounts": [], + "waits": [] + }, + "linked_actions": [] + } + ], + "total_resources": null, + "self_delegated_bandwidth": null, + "refund_request": null, + "voter_info": null, + "rex_info": null, + "subjective_cpu_bill_limit": { + "used": 0, + "available": 0, + "max": 0, + "last_usage_update_time": "2000-01-01T00:00:00.000", + "current_used": 0 + }, + "eosio_any_linked_actions": [] + } + "#; + + let res = serde_json::from_str::(&simple_account_json).unwrap(); println!("{:#?}", res); -} \ No newline at end of file +} + + #[test] + fn deserialize_detailed_account() { + // This detailed account response contains additional fields compared to the simple account (see test above), + // in particular `total_resources`, `self_delegated_bandwidth`, `refund_request`, `voter_info`, and `rex_info`. + let detailed_account_json = r#" + { + "account_name": "alice", + "head_block_num": 56, + "head_block_time": "2024-08-29T15:27:24.500", + "privileged": false, + "last_code_update": "1970-01-01T00:00:00.000", + "created": "2024-08-29T14:06:02.000", + "core_liquid_balance": "100.0000 TLOS", + "ram_quota": 610645714, + "net_weight": 10000000, + "cpu_weight": 10000000, + "net_limit": { + "used": 0, + "available": "95719449600", + "max": "95719449600", + "last_usage_update_time": "2024-08-29T14:06:02.000", + "current_used": 0 + }, + "cpu_limit": { + "used": 0, + "available": "364783305600", + "max": "364783305600", + "last_usage_update_time": "2024-08-29T14:06:02.000", + "current_used": 0 + }, + "ram_usage": 3566, + "permissions": [ + { + "perm_name": "active", + "parent": "owner", + "required_auth": { + "threshold": 1, + "keys": [ + { + "key": "EOS77jzbmLuakAHpm2Q5ew8EL7Y7gGkfSzqJCmCNDDXWEsBP3xnDc", + "weight": 1 + } + ], + "accounts": [], + "waits": [] + }, + "linked_actions": [] + }, + { + "perm_name": "owner", + "parent": "", + "required_auth": { + "threshold": 1, + "keys": [ + { + "key": "EOS77jzbmLuakAHpm2Q5ew8EL7Y7gGkfSzqJCmCNDDXWEsBP3xnDc", + "weight": 1 + } + ], + "accounts": [], + "waits": [] + }, + "linked_actions": [] + } + ], + "total_resources": { + "owner": "alice", + "net_weight": "1000.0000 TLOS", + "cpu_weight": "1000.0000 TLOS", + "ram_bytes": 610644314 + }, + "self_delegated_bandwidth": { + "from": "alice", + "to": "alice", + "net_weight": "1000.0000 TLOS", + "cpu_weight": "1000.0000 TLOS" + }, + "refund_request": null, + "voter_info": { + "owner": "alice", + "proxy": "", + "producers": [], + "staked": 20000000, + "last_stake": 0, + "last_vote_weight": "0.00000000000000000", + "proxied_vote_weight": "0.00000000000000000", + "is_proxy": 0, + "flags1": 0, + "reserved2": 0, + "reserved3": "0 " + }, + "rex_info": null, + "subjective_cpu_bill_limit": { + "used": 0, + "available": 0, + "max": 0, + "last_usage_update_time": "2000-01-01T00:00:00.000", + "current_used": 0 + }, + "eosio_any_linked_actions": [] + } + "#; + + let res = serde_json::from_str::(&detailed_account_json).unwrap(); + println!("{:#?}", res); + } + + #[test] + fn deserialize_account_without_core_liquid_balance() { + // This simple account response doesn't contain details about `total_resources`, `self_delegated_bandwidth`, + // `refund_request`, `voter_info`, and `rex_info`. + // Such fields are null. + let detailed_account_json = r#" + { + "account_name": "alice", + "head_block_num": 56, + "head_block_time": "2024-08-29T15:46:42.000", + "privileged": false, + "last_code_update": "1970-01-01T00:00:00.000", + "created": "2024-08-29T14:06:02.000", + "ram_quota": 610645714, + "net_weight": 10000000, + "cpu_weight": 10000000, + "net_limit": { + "used": 0, + "available": "95719449600", + "max": "95719449600", + "last_usage_update_time": "2024-08-29T14:06:02.000", + "current_used": 0 + }, + "cpu_limit": { + "used": 0, + "available": "364783305600", + "max": "364783305600", + "last_usage_update_time": "2024-08-29T14:06:02.000", + "current_used": 0 + }, + "ram_usage": 3566, + "permissions": [ + { + "perm_name": "active", + "parent": "owner", + "required_auth": { + "threshold": 1, + "keys": [ + { + "key": "EOS77jzbmLuakAHpm2Q5ew8EL7Y7gGkfSzqJCmCNDDXWEsBP3xnDc", + "weight": 1 + } + ], + "accounts": [], + "waits": [] + }, + "linked_actions": [] + }, + { + "perm_name": "owner", + "parent": "", + "required_auth": { + "threshold": 1, + "keys": [ + { + "key": "EOS77jzbmLuakAHpm2Q5ew8EL7Y7gGkfSzqJCmCNDDXWEsBP3xnDc", + "weight": 1 + } + ], + "accounts": [], + "waits": [] + }, + "linked_actions": [] + } + ], + "total_resources": { + "owner": "alice", + "net_weight": "1000.0000 TLOS", + "cpu_weight": "1000.0000 TLOS", + "ram_bytes": 610644314 + }, + "self_delegated_bandwidth": { + "from": "alice", + "to": "alice", + "net_weight": "1000.0000 TLOS", + "cpu_weight": "1000.0000 TLOS" + }, + "refund_request": null, + "voter_info": { + "owner": "alice", + "proxy": "", + "producers": [], + "staked": 20000000, + "last_stake": 0, + "last_vote_weight": "0.00000000000000000", + "proxied_vote_weight": "0.00000000000000000", + "is_proxy": 0, + "flags1": 0, + "reserved2": 0, + "reserved3": "0 " + }, + "rex_info": null, + "subjective_cpu_bill_limit": { + "used": 0, + "available": 0, + "max": 0, + "last_usage_update_time": "2000-01-01T00:00:00.000", + "current_used": 0 + }, + "eosio_any_linked_actions": [] + } + "#; + + let res = serde_json::from_str::(&detailed_account_json).unwrap(); + println!("{:#?}", res); + } +} From f483c55618683b9a137d7a3427e41210dc73c14d Mon Sep 17 00:00:00 2001 From: Paolo Tagliaferri Date: Wed, 11 Sep 2024 17:58:29 +0200 Subject: [PATCH 15/26] Fixed the deserialization of `get_account` responses The deserialization of the `core_liquid_balance` wasn't taking into account that such field could be omitted. --- crates/antelope/src/api/v1/structs.rs | 16 ++++++++++------ crates/antelope/src/chain/asset.rs | 26 ++++++++++++++++++++++++++ crates/antelope/tests/client.rs | 2 +- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/crates/antelope/src/api/v1/structs.rs b/crates/antelope/src/api/v1/structs.rs index b6ab57b..0f5ffb8 100644 --- a/crates/antelope/src/api/v1/structs.rs +++ b/crates/antelope/src/api/v1/structs.rs @@ -11,7 +11,7 @@ use crate::chain::public_key::PublicKey; use crate::chain::signature::Signature; use crate::chain::{ action::{Action, PermissionLevel}, - asset::{deserialize_asset, Asset}, + asset::{deserialize_asset, deserialize_optional_asset, Asset}, authority::Authority, block_id::{deserialize_block_id, deserialize_optional_block_id, BlockId}, checksum::{deserialize_checksum256, Checksum160, Checksum256}, @@ -459,8 +459,12 @@ pub struct AccountObject { pub last_code_update: TimePoint, #[serde(deserialize_with = "deserialize_timepoint")] pub created: TimePoint, - #[serde(deserialize_with = "deserialize_asset")] - pub core_liquid_balance: Asset, + #[serde( + deserialize_with = "deserialize_optional_asset", + default, + skip_serializing_if = "Option::is_none" + )] + pub core_liquid_balance: Option, pub ram_quota: i64, pub net_weight: i64, pub cpu_weight: i64, @@ -954,7 +958,7 @@ where mod tests { use crate::api::v1::structs::AccountObject; -#[test] + #[test] fn deserialize_simple_account() { // This simple account response doesn't contain details about `total_resources`, `self_delegated_bandwidth`, // `refund_request`, `voter_info`, and `rex_info`. @@ -1037,8 +1041,8 @@ mod tests { "#; let res = serde_json::from_str::(&simple_account_json).unwrap(); - println!("{:#?}", res); -} + println!("{:#?}", res); + } #[test] fn deserialize_detailed_account() { diff --git a/crates/antelope/src/chain/asset.rs b/crates/antelope/src/chain/asset.rs index 390b03b..3faaf6d 100644 --- a/crates/antelope/src/chain/asset.rs +++ b/crates/antelope/src/chain/asset.rs @@ -431,6 +431,32 @@ where deserializer.deserialize_str(AssetVisitor) } +pub(crate) fn deserialize_optional_asset<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + struct OptionalAssetVisitor; + + impl<'de> de::Visitor<'de> for OptionalAssetVisitor { + type Value = Option; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str( + "an optional string representing an asset in the format 'amount symbol_code'", + ) + } + + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + Ok(Some(deserialize_asset(deserializer)?)) + } + } + + deserializer.deserialize_option(OptionalAssetVisitor) +} + #[derive(Copy, Clone, Default, Eq, PartialEq, Serialize, Deserialize)] pub struct ExtendedAsset { quantity: Asset, diff --git a/crates/antelope/tests/client.rs b/crates/antelope/tests/client.rs index 46f71cd..cbe2c5a 100644 --- a/crates/antelope/tests/client.rs +++ b/crates/antelope/tests/client.rs @@ -150,7 +150,7 @@ async fn chan_get_account() { assert_eq!( account.core_liquid_balance, - Asset::from_string("128559.5000 TLOS") + Some(Asset::from_string("128559.5000 TLOS")) ); } Err(e) => { From 69a95fe29685b890ba617bc06cc3c3b8a66d2666 Mon Sep 17 00:00:00 2001 From: Jesse Schulman Date: Tue, 17 Sep 2024 13:35:49 -0700 Subject: [PATCH 16/26] Adding support for passing timeout to rewqest ClientBuilder --- crates/antelope/src/api/client.rs | 10 +++++++--- crates/antelope/src/api/default_provider.rs | 9 +++++++-- crates/antelope/src/api/v1/structs.rs | 1 + 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/crates/antelope/src/api/client.rs b/crates/antelope/src/api/client.rs index 4e1574d..32609e7 100644 --- a/crates/antelope/src/api/client.rs +++ b/crates/antelope/src/api/client.rs @@ -40,15 +40,19 @@ pub struct APIClient { } impl APIClient

{ - pub fn default_provider(base_url: String) -> Result, String> { - Self::default_provider_debug(base_url, false) + pub fn default_provider( + base_url: String, + timeout: Option, + ) -> Result, String> { + Self::default_provider_debug(base_url, timeout, false) } pub fn default_provider_debug( base_url: String, + timeout: Option, debug: bool, ) -> Result, String> { - let mut provider = DefaultProvider::new(base_url).unwrap(); + let mut provider = DefaultProvider::new(base_url, timeout).unwrap(); provider.set_debug(debug); APIClient::custom_provider(provider) diff --git a/crates/antelope/src/api/default_provider.rs b/crates/antelope/src/api/default_provider.rs index 6cc4a1c..9d4a8ae 100644 --- a/crates/antelope/src/api/default_provider.rs +++ b/crates/antelope/src/api/default_provider.rs @@ -12,8 +12,13 @@ pub struct DefaultProvider { } impl DefaultProvider { - pub fn new(base_url: String) -> Result { - let client = Client::builder().build(); + pub fn new(base_url: String, timeout: Option) -> Result { + let mut client_builder = Client::builder(); + if timeout.is_some() { + client_builder = + client_builder.timeout(std::time::Duration::from_secs(timeout.unwrap())); + } + let client = client_builder.build(); if client.is_err() { let err = client.err(); let mut err_message = String::from("Error building http client"); diff --git a/crates/antelope/src/api/v1/structs.rs b/crates/antelope/src/api/v1/structs.rs index 0f5ffb8..dee7af4 100644 --- a/crates/antelope/src/api/v1/structs.rs +++ b/crates/antelope/src/api/v1/structs.rs @@ -440,6 +440,7 @@ impl GetTableRowsParams { } } +#[derive(Debug)] pub struct GetTableRowsResponse { pub rows: Vec, pub more: bool, From d06e040263df6f74b521dc43cdb8affd340e135b Mon Sep 17 00:00:00 2001 From: Jesse Schulman Date: Sun, 29 Sep 2024 21:46:11 -0700 Subject: [PATCH 17/26] Support for encode/decode of Webauthn (WA) type signatures --- crates/antelope/src/base58.rs | 4 +- crates/antelope/src/chain/key_type.rs | 15 ++++++++ crates/antelope/src/chain/signature.rs | 39 +++++++++++++++----- crates/antelope/src/crypto/generate.rs | 1 + crates/antelope/src/crypto/get_public.rs | 1 + crates/antelope/src/crypto/recover.rs | 1 + crates/antelope/src/crypto/shared_secrets.rs | 1 + crates/antelope/src/crypto/sign.rs | 1 + crates/antelope/src/crypto/verify.rs | 1 + crates/antelope/tests/serializer.rs | 38 +++++++++---------- 10 files changed, 72 insertions(+), 30 deletions(-) diff --git a/crates/antelope/src/base58.rs b/crates/antelope/src/base58.rs index 5087cb7..63622b2 100644 --- a/crates/antelope/src/base58.rs +++ b/crates/antelope/src/base58.rs @@ -81,11 +81,12 @@ pub fn decode_public_key(value: &str) -> Result<(KeyType, Vec), String> { let key_type = match parts[1] { "K1" => KeyType::K1, "R1" => KeyType::R1, - // ... handle other key types ... + "WA" => KeyType::WA, _ => return Err("Invalid key type".to_string()), }; let size = match key_type { KeyType::K1 | KeyType::R1 => Some(32), + KeyType::WA => None // ... other cases ... }; let data = decode_ripemd160_check(parts[2], size, Option::from(key_type), false).unwrap(); @@ -113,6 +114,7 @@ pub fn decode_key(value: &str, ignore_checksum: bool) -> Result<(KeyType, Vec Some(32), + KeyType::WA => None // ... other cases ... }; let data_result = decode_ripemd160_check(parts[2], size, Some(key_type), ignore_checksum); diff --git a/crates/antelope/src/chain/key_type.rs b/crates/antelope/src/chain/key_type.rs index 0b2fd3d..bbddf48 100644 --- a/crates/antelope/src/chain/key_type.rs +++ b/crates/antelope/src/chain/key_type.rs @@ -9,6 +9,7 @@ pub enum KeyType { #[default] K1, R1, + WA, // ... other variants ... } @@ -27,6 +28,10 @@ impl KeyTypeTrait for KeyType { if s == "R1" { return Ok(KeyType::R1); } + + if s == "WA" { + return Ok(KeyType::WA); + } Err(format!("Unknown key type {s}")) } @@ -39,6 +44,11 @@ impl KeyTypeTrait for KeyType { if i == 1 { return Ok(KeyType::R1); } + + if i == 2 { + return Ok(KeyType::WA); + } + Err(format!("Unknown KeyType index {i}")) } @@ -46,6 +56,7 @@ impl KeyTypeTrait for KeyType { match self { KeyType::K1 => 0, KeyType::R1 => 1, + KeyType::WA => 2, } } } @@ -59,6 +70,9 @@ impl Display for KeyType { KeyType::R1 => { write!(f, "R1") } + KeyType::WA => { + write!(f, "WA") + } } } } @@ -73,6 +87,7 @@ impl Packer for KeyType { match self { KeyType::K1 => data[0] = 0u8, KeyType::R1 => data[0] = 1u8, + KeyType::WA => data[0] = 2u8, } self.size() } diff --git a/crates/antelope/src/chain/signature.rs b/crates/antelope/src/chain/signature.rs index d46e770..a6c15bd 100644 --- a/crates/antelope/src/chain/signature.rs +++ b/crates/antelope/src/chain/signature.rs @@ -20,6 +20,7 @@ use crate::{ crypto::{recover::recover_message, verify::verify_message}, util::slice_copy, }; +use crate::chain::varint::VarUint32; #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct Signature { @@ -74,13 +75,10 @@ impl Signature { } let parts: Vec<&str> = s.split('_').collect(); let key_type = KeyType::from_string(parts[1]).unwrap(); - let size: Option = Some(65); - // TODO: add back this logic when other key types are supported and have a - // different length match key_type { - // KeyType::K1 | KeyType::R1 => { - // size = Some(65); - // } - // } + let size = match key_type { + KeyType::K1 | KeyType::R1 => Some(65), + KeyType::WA => None, + }; let value = base58::decode_ripemd160_check(parts[2], size, Option::from(key_type), false).unwrap(); @@ -193,7 +191,7 @@ impl Default for Signature { impl Packer for Signature { fn size(&self) -> usize { - 66 + 1 + self.value.len() } fn pack(&self, enc: &mut Encoder) -> usize { @@ -204,10 +202,31 @@ impl Packer for Signature { } fn unpack(&mut self, data: &[u8]) -> usize { + self.key_type = KeyType::from_index(data[0]).unwrap(); + match self.key_type { + KeyType::K1 | KeyType::R1 => { + self.value = data[1..66].to_vec(); + } + KeyType::WA => { + let mut size = 66; // size to start = 1 byte for key type, 65 bytes for compact signature + let mut auth_data = VarUint32::default(); + // unpack() returns how many bytes were read to unpack the value + size += auth_data.unpack(&data[size..]); // after the compact sig comes a varuint32 to tell us the size of the auth data + size += auth_data.value() as usize; // add the auth data size + let mut client_json = VarUint32::default(); + size += client_json.unpack(&data[size..]); // read the varuint32 size of the client_json + size += client_json.value() as usize; // add the client_json size + // set value to be the whole payload (after the key type byte): + // compact sig, + // varuint32 auth data size, + // auth data, + // varuint32 client_json size, + // client_json + self.value = data[1..size].to_vec(); + } + } let size = self.size(); assert!(data.len() >= size, "Signature::unpack: buffer overflow"); - self.key_type = KeyType::from_index(data[0]).unwrap(); - self.value = data[1..size].to_vec(); self.size() } } diff --git a/crates/antelope/src/crypto/generate.rs b/crates/antelope/src/crypto/generate.rs index acffd92..d8c8f02 100644 --- a/crates/antelope/src/crypto/generate.rs +++ b/crates/antelope/src/crypto/generate.rs @@ -20,5 +20,6 @@ pub fn generate(curve_type: KeyType) -> Result, String> { let encoded_point = public_key.to_encoded_point(true); Ok(encoded_point.as_bytes().to_vec()) } + KeyType::WA => Err("Unsupported key type".to_string()), } } diff --git a/crates/antelope/src/crypto/get_public.rs b/crates/antelope/src/crypto/get_public.rs index f639c77..f41f319 100644 --- a/crates/antelope/src/crypto/get_public.rs +++ b/crates/antelope/src/crypto/get_public.rs @@ -26,5 +26,6 @@ pub fn get_public(priv_key: Vec, curve_type: KeyType) -> Result, Str let encoded_point = public_key.to_encoded_point(true); Ok(encoded_point.as_bytes().to_vec()) } + KeyType::WA => Err("Unsupported key type".to_string()), } } diff --git a/crates/antelope/src/crypto/recover.rs b/crates/antelope/src/crypto/recover.rs index df49a75..6a79e20 100644 --- a/crates/antelope/src/crypto/recover.rs +++ b/crates/antelope/src/crypto/recover.rs @@ -36,5 +36,6 @@ pub fn recover_message(signature: &Signature, message_bytes: &Vec) -> Public let compressed_bytes = compressed.as_bytes(); PublicKey::from_bytes(compressed_bytes.to_vec(), key_type) } + KeyType::WA => panic!("Unsupported key type"), } } diff --git a/crates/antelope/src/crypto/shared_secrets.rs b/crates/antelope/src/crypto/shared_secrets.rs index 6b30942..333da3d 100644 --- a/crates/antelope/src/crypto/shared_secrets.rs +++ b/crates/antelope/src/crypto/shared_secrets.rs @@ -33,5 +33,6 @@ pub fn shared_secret( ); Ok(shared_secret.raw_secret_bytes().to_vec()) } + KeyType::WA => Err("Unsupported key type".to_string()), } } diff --git a/crates/antelope/src/crypto/sign.rs b/crates/antelope/src/crypto/sign.rs index 19b356e..430b50c 100644 --- a/crates/antelope/src/crypto/sign.rs +++ b/crates/antelope/src/crypto/sign.rs @@ -74,6 +74,7 @@ pub fn sign(secret: Vec, message: &Vec, key_type: KeyType) -> Result Err("Unsupported key type".to_string()), } } diff --git a/crates/antelope/src/crypto/verify.rs b/crates/antelope/src/crypto/verify.rs index 10cd2f3..8b784fe 100644 --- a/crates/antelope/src/crypto/verify.rs +++ b/crates/antelope/src/crypto/verify.rs @@ -34,5 +34,6 @@ pub fn verify_message(signature: &Signature, message_bytes: &Vec, pub_key: & let verification = verifying_key.verify(message_bytes.as_slice(), &sig_result); verification.is_ok() } + KeyType::WA => panic!("Unsupported key type"), } } diff --git a/crates/antelope/tests/serializer.rs b/crates/antelope/tests/serializer.rs index 3747cc3..c4a7694 100644 --- a/crates/antelope/tests/serializer.rs +++ b/crates/antelope/tests/serializer.rs @@ -316,27 +316,27 @@ fn signature() { assert_eq!(decoded_size, 66); assert_eq!(decoded_sig.to_string(), json); } -/* -test('signature (wa)', function () { - const sig = - 'SIG_WA_2AAAuLJS3pLPgkQQPqLsehL6VeRBaAZS7NYM91UYRUrSAEfUvzKN7DCSwhjsDqe74cZNWKUU' + - 'GAHGG8ddSA7cvUxChbfKxLSrDCpwe6MVUqz4PDdyCt5tXhEJmKekxG1o1ucY3LVj8Vi9rRbzAkKPCzW' + - 'qC8cPcUtpLHNG8qUKkQrN4Xuwa9W8rsBiUKwZv1ToLyVhLrJe42pvHYBXicp4E8qec5E4m6SX11KuXE' + - 'RFcV48Mhiie2NyaxdtNtNzQ5XZ5hjBkxRujqejpF4SNHvdAGKRBbvhkiPLA25FD3xoCbrN26z72' - const data = - '0220d9132bbdb219e4e2d99af9c507e3597f86b615814f36672d501034861792bbcf21a46d1a2eb12bace4a29100b942f987494f3aefc8' + - 'efb2d5af4d4d8de3e0871525aa14905af60ca17a1bb80e0cf9c3b46908a0f14f72567a2f140c3a3bd2ef074c010000006d737b226f7269' + - '67696e223a2268747470733a2f2f6b656f73642e696e76616c6964222c2274797065223a22776562617574686e2e676574222c22636861' + - '6c6c656e6765223a226f69567235794848304a4336453962446675347142735a6a527a70416c5131505a50436e5974766850556b3d227d' - const object = Signature.from(sig) - const json = `"${sig}"` - assert.equal(Serializer.encode({object}).hexString, data) - assert.equal(JSON.stringify(Serializer.decode({data, type: Signature})), json) - assert.equal(JSON.stringify(Serializer.decode({json, type: 'signature'})), json) - assert.equal(JSON.stringify(object), json) -}) +#[test] +fn signature_wa() { + let data = + hex_to_bytes("0220d9132bbdb219e4e2d99af9c507e3597f86b615814f36672d501034861792bbcf21a46d1a2eb12bace4a29100b942f987494f3aefc8efb2d5af4d4d8de3e0871525aa14905af60ca17a1bb80e0cf9c3b46908a0f14f72567a2f140c3a3bd2ef074c010000006d737b226f726967696e223a2268747470733a2f2f6b656f73642e696e76616c6964222c2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a226f69567235794848304a4336453962446675347142735a6a527a70416c5131505a50436e5974766850556b3d227d"); + let sig_str = + "SIG_WA_2AAAuLJS3pLPgkQQPqLsehL6VeRBaAZS7NYM91UYRUrSAEfUvzKN7DCSwhjsDqe74cZNWKUUGAHGG8ddSA7cvUxChbfKxLSrDCpwe6MVUqz4PDdyCt5tXhEJmKekxG1o1ucY3LVj8Vi9rRbzAkKPCzWqC8cPcUtpLHNG8qUKkQrN4Xuwa9W8rsBiUKwZv1ToLyVhLrJe42pvHYBXicp4E8qec5E4m6SX11KuXERFcV48Mhiie2NyaxdtNtNzQ5XZ5hjBkxRujqejpF4SNHvdAGKRBbvhkiPLA25FD3xoCbrN26z72"; + + let sig = Signature::from_string(sig_str).unwrap(); + let encoded = Encoder::pack(&sig); + assert_eq!(encoded, data); + let mut decoder = Decoder::new(data.as_slice()); + let decoded_sig = &mut Signature::default(); + let decoded_size = decoder.unpack(decoded_sig); + let decoded_sig_str = decoded_sig.to_string(); + assert_eq!(decoded_size, 220); + assert_eq!(decoded_sig_str, sig_str); +} + +/* test('time point', function () { const data = 'f8b88a3cd5620400' const object = TimePoint.from(1234567890123000) From 5035d14609dd6b415f4f4a359361b2341f39d936 Mon Sep 17 00:00:00 2001 From: Jesse Schulman Date: Sun, 29 Sep 2024 21:47:38 -0700 Subject: [PATCH 18/26] formatting --- crates/antelope/src/base58.rs | 6 ++---- crates/antelope/src/chain/key_type.rs | 6 +++--- crates/antelope/src/chain/signature.rs | 14 +++++++------- crates/antelope/tests/serializer.rs | 8 +++----- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/crates/antelope/src/base58.rs b/crates/antelope/src/base58.rs index 63622b2..58ec731 100644 --- a/crates/antelope/src/base58.rs +++ b/crates/antelope/src/base58.rs @@ -86,8 +86,7 @@ pub fn decode_public_key(value: &str) -> Result<(KeyType, Vec), String> { }; let size = match key_type { KeyType::K1 | KeyType::R1 => Some(32), - KeyType::WA => None - // ... other cases ... + KeyType::WA => None, // ... other cases ... }; let data = decode_ripemd160_check(parts[2], size, Option::from(key_type), false).unwrap(); Ok((key_type, data)) @@ -114,8 +113,7 @@ pub fn decode_key(value: &str, ignore_checksum: bool) -> Result<(KeyType, Vec Some(32), - KeyType::WA => None - // ... other cases ... + KeyType::WA => None, // ... other cases ... }; let data_result = decode_ripemd160_check(parts[2], size, Some(key_type), ignore_checksum); if data_result.is_err() { diff --git a/crates/antelope/src/chain/key_type.rs b/crates/antelope/src/chain/key_type.rs index bbddf48..ddd33bd 100644 --- a/crates/antelope/src/chain/key_type.rs +++ b/crates/antelope/src/chain/key_type.rs @@ -28,7 +28,7 @@ impl KeyTypeTrait for KeyType { if s == "R1" { return Ok(KeyType::R1); } - + if s == "WA" { return Ok(KeyType::WA); } @@ -44,11 +44,11 @@ impl KeyTypeTrait for KeyType { if i == 1 { return Ok(KeyType::R1); } - + if i == 2 { return Ok(KeyType::WA); } - + Err(format!("Unknown KeyType index {i}")) } diff --git a/crates/antelope/src/chain/signature.rs b/crates/antelope/src/chain/signature.rs index a6c15bd..116a34e 100644 --- a/crates/antelope/src/chain/signature.rs +++ b/crates/antelope/src/chain/signature.rs @@ -9,6 +9,7 @@ use serde::{ Deserialize, Deserializer, Serialize, }; +use crate::chain::varint::VarUint32; use crate::{ base58, base58::encode_ripemd160_check, @@ -20,7 +21,6 @@ use crate::{ crypto::{recover::recover_message, verify::verify_message}, util::slice_copy, }; -use crate::chain::varint::VarUint32; #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct Signature { @@ -216,12 +216,12 @@ impl Packer for Signature { let mut client_json = VarUint32::default(); size += client_json.unpack(&data[size..]); // read the varuint32 size of the client_json size += client_json.value() as usize; // add the client_json size - // set value to be the whole payload (after the key type byte): - // compact sig, - // varuint32 auth data size, - // auth data, - // varuint32 client_json size, - // client_json + // set value to be the whole payload (after the key type byte): + // compact sig, + // varuint32 auth data size, + // auth data, + // varuint32 client_json size, + // client_json self.value = data[1..size].to_vec(); } } diff --git a/crates/antelope/tests/serializer.rs b/crates/antelope/tests/serializer.rs index c4a7694..b71d717 100644 --- a/crates/antelope/tests/serializer.rs +++ b/crates/antelope/tests/serializer.rs @@ -319,11 +319,9 @@ fn signature() { #[test] fn signature_wa() { - let data = - hex_to_bytes("0220d9132bbdb219e4e2d99af9c507e3597f86b615814f36672d501034861792bbcf21a46d1a2eb12bace4a29100b942f987494f3aefc8efb2d5af4d4d8de3e0871525aa14905af60ca17a1bb80e0cf9c3b46908a0f14f72567a2f140c3a3bd2ef074c010000006d737b226f726967696e223a2268747470733a2f2f6b656f73642e696e76616c6964222c2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a226f69567235794848304a4336453962446675347142735a6a527a70416c5131505a50436e5974766850556b3d227d"); - let sig_str = - "SIG_WA_2AAAuLJS3pLPgkQQPqLsehL6VeRBaAZS7NYM91UYRUrSAEfUvzKN7DCSwhjsDqe74cZNWKUUGAHGG8ddSA7cvUxChbfKxLSrDCpwe6MVUqz4PDdyCt5tXhEJmKekxG1o1ucY3LVj8Vi9rRbzAkKPCzWqC8cPcUtpLHNG8qUKkQrN4Xuwa9W8rsBiUKwZv1ToLyVhLrJe42pvHYBXicp4E8qec5E4m6SX11KuXERFcV48Mhiie2NyaxdtNtNzQ5XZ5hjBkxRujqejpF4SNHvdAGKRBbvhkiPLA25FD3xoCbrN26z72"; - + let data = hex_to_bytes("0220d9132bbdb219e4e2d99af9c507e3597f86b615814f36672d501034861792bbcf21a46d1a2eb12bace4a29100b942f987494f3aefc8efb2d5af4d4d8de3e0871525aa14905af60ca17a1bb80e0cf9c3b46908a0f14f72567a2f140c3a3bd2ef074c010000006d737b226f726967696e223a2268747470733a2f2f6b656f73642e696e76616c6964222c2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a226f69567235794848304a4336453962446675347142735a6a527a70416c5131505a50436e5974766850556b3d227d"); + let sig_str = "SIG_WA_2AAAuLJS3pLPgkQQPqLsehL6VeRBaAZS7NYM91UYRUrSAEfUvzKN7DCSwhjsDqe74cZNWKUUGAHGG8ddSA7cvUxChbfKxLSrDCpwe6MVUqz4PDdyCt5tXhEJmKekxG1o1ucY3LVj8Vi9rRbzAkKPCzWqC8cPcUtpLHNG8qUKkQrN4Xuwa9W8rsBiUKwZv1ToLyVhLrJe42pvHYBXicp4E8qec5E4m6SX11KuXERFcV48Mhiie2NyaxdtNtNzQ5XZ5hjBkxRujqejpF4SNHvdAGKRBbvhkiPLA25FD3xoCbrN26z72"; + let sig = Signature::from_string(sig_str).unwrap(); let encoded = Encoder::pack(&sig); assert_eq!(encoded, data); From 79fa958f4216a8431f9cf8b64a52a63c76f437df Mon Sep 17 00:00:00 2001 From: Jesse Schulman Date: Thu, 10 Oct 2024 14:37:15 -0700 Subject: [PATCH 19/26] Better handling for inconsistent types in SendTransactionResponse --- crates/antelope/src/api/v1/chain.rs | 2 +- crates/antelope/src/api/v1/structs.rs | 46 ++++++++++- crates/antelope/tests/client.rs | 87 +++++++++++++++++++- crates/antelope/tests/utils/mock_provider.rs | 2 +- 4 files changed, 131 insertions(+), 6 deletions(-) diff --git a/crates/antelope/src/api/v1/chain.rs b/crates/antelope/src/api/v1/chain.rs index 242e752..9a529be 100644 --- a/crates/antelope/src/api/v1/chain.rs +++ b/crates/antelope/src/api/v1/chain.rs @@ -184,7 +184,7 @@ impl ChainAPI { Err(e) => { // If parsing the error response also fails, consider it an encoding error Err(ClientError::ENCODING(EncodingError { - message: format!("Failed to parse response: {}", e), + message: format!("Failed to parse response: {} Raw response was: {}", e, result), })) } } diff --git a/crates/antelope/src/api/v1/structs.rs b/crates/antelope/src/api/v1/structs.rs index dee7af4..037d235 100644 --- a/crates/antelope/src/api/v1/structs.rs +++ b/crates/antelope/src/api/v1/structs.rs @@ -191,7 +191,7 @@ pub struct SendTransactionResponseExceptionStack { #[derive(Debug, Serialize, Deserialize)] pub struct SendTransactionResponseError { - pub code: u32, + pub code: Option, pub name: String, pub what: String, pub stack: Option>, @@ -273,9 +273,11 @@ pub struct ActionTrace { pub receiver: Name, pub act: Action, pub context_free: bool, + #[serde(deserialize_with = "deserialize_u64_from_string_or_u64")] pub elapsed: u64, pub console: String, pub trx_id: String, + #[serde(deserialize_with = "deserialize_u64_from_string_or_u64")] pub block_num: u64, pub block_time: String, pub producer_block_id: Option, @@ -290,10 +292,14 @@ pub struct ActionReceipt { #[serde(deserialize_with = "deserialize_name")] pub receiver: Name, pub act_digest: String, + #[serde(deserialize_with = "deserialize_u64_from_string_or_u64")] pub global_sequence: u64, + #[serde(deserialize_with = "deserialize_u64_from_string_or_u64")] pub recv_sequence: u64, pub auth_sequence: Vec, + #[serde(deserialize_with = "deserialize_u64_from_string_or_u64")] pub code_sequence: u64, + #[serde(deserialize_with = "deserialize_u64_from_string_or_u64")] pub abi_sequence: u64, } @@ -859,6 +865,44 @@ where deserializer.deserialize_any(NumberToBoolVisitor) } +fn deserialize_u64_from_string_or_u64<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + struct U64OrStringVisitor; + + impl<'de> serde::de::Visitor<'de> for U64OrStringVisitor { + type Value = u64; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("an integer or a string representation of an integer") + } + + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + value.parse::().map_err(E::custom) + } + + fn visit_u64(self, value: u64) -> Result + where + E: serde::de::Error, + { + Ok(value) + } + + fn visit_i64(self, value: i64) -> Result + where + E: serde::de::Error, + { + u64::try_from(value).map_err(|_| E::custom("u64 value too large for i64")) + } + } + + deserializer.deserialize_any(U64OrStringVisitor) +} + fn deserialize_i64_from_string_or_i64<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, diff --git a/crates/antelope/tests/client.rs b/crates/antelope/tests/client.rs index cbe2c5a..9e5517d 100644 --- a/crates/antelope/tests/client.rs +++ b/crates/antelope/tests/client.rs @@ -1,5 +1,5 @@ use antelope::api::client::DefaultProvider; -use antelope::api::v1::structs::{ErrorResponse, IndexPosition, TableIndexType}; +use antelope::api::v1::structs::{ErrorResponse, IndexPosition, SendTransactionResponse, TableIndexType}; use antelope::{ api::{ client::APIClient, @@ -121,7 +121,7 @@ async fn chain_send_transaction() { println!("{:?}", failure_response); match failure_response { ClientError::SERVER(err) => { - assert_eq!(err.error.code, 3050003); + assert_eq!(err.error.code, Some(3050003)); } _ => { assert!( @@ -195,6 +195,87 @@ pub async fn chain_get_abi() { assert_eq!(abi_object.abi.tables[0].name, name!("accounts")); } +#[test] +fn test_send_transaction_response() { + let response_json = r#"{ + "transaction_id": "6eee2f00f7e7771c40f6b0b8f837557fcd9317711bed53279a65c7b8a20dcf91", + "processed": { + "id": "6eee2f00f7e7771c40f6b0b8f837557fcd9317711bed53279a65c7b8a20dcf91", + "block_num": 367207774, + "block_time": "2024-10-10T16:52:50.000", + "producer_block_id": null, + "receipt": { + "status": "executed", + "cpu_usage_us": 1423, + "net_usage_words": 36 + }, + "elapsed": 1423, + "net_usage": 288, + "scheduled": false, + "action_traces": [ + { + "action_ordinal": 1, + "creator_action_ordinal": 0, + "closest_unnotified_ancestor_action_ordinal": 0, + "receipt": { + "receiver": "eosio.evm", + "act_digest": "8a73d9427ca99c95ce1d66588a6e3107c15db57b7e2358fd324fe6dcdc0c4296", + "global_sequence": "10128941153", + "recv_sequence": 4471374, + "auth_sequence": [ + [ + "rpc.evm", + 4249842 + ] + ], + "code_sequence": 5, + "abi_sequence": 2 + }, + "receiver": "eosio.evm", + "act": { + "account": "eosio.evm", + "name": "raw", + "authorization": [ + { + "actor": "rpc.evm", + "permission": "rpc" + } + ], + "data": { + "ram_payer": "eosio.evm", + "tx": "f8ab82043c85792c395db082b62694eeca10921a5b3dcd2acb8ef2cb4b1b4d6a69b16e80b844095ea7b30000000000000000000000009ef9c57754ed079d750016b802dccd45d0ab66f8000000000000000000000000000000000000000000000000d02ab486cedc000074a0d1bb4f832c6ed0fb7abffc2133621d051c6af8084915701363fa63f307f64eeda07994e5abad4b1cdc5dea37b7c9ff59c9fa10017af29df222262463769d8fe51c", + "estimate_gas": 0, + "sender": null + }, + "hex_data": "0000905b01ea3055ad01f8ab82043c85792c395db082b62694eeca10921a5b3dcd2acb8ef2cb4b1b4d6a69b16e80b844095ea7b30000000000000000000000009ef9c57754ed079d750016b802dccd45d0ab66f8000000000000000000000000000000000000000000000000d02ab486cedc000074a0d1bb4f832c6ed0fb7abffc2133621d051c6af8084915701363fa63f307f64eeda07994e5abad4b1cdc5dea37b7c9ff59c9fa10017af29df222262463769d8fe51c0000" + }, + "context_free": false, + "elapsed": 1249, + "console": "RECIPT DATA", + "trx_id": "6eee2f00f7e7771c40f6b0b8f837557fcd9317711bed53279a65c7b8a20dcf91", + "block_num": 367207774, + "block_time": "2024-10-10T16:52:50.000", + "producer_block_id": null, + "account_ram_deltas": [], + "except": null, + "error_code": null, + "return_value_hex_data": "" + } + ], + "account_ram_delta": null, + "except": null, + "error_code": null + } + }"#; + + let parsed = serde_json::from_str::(&response_json); + assert!(parsed.is_ok()); + let parsed = parsed.unwrap(); + let traces = parsed.processed.action_traces; + assert_eq!(traces.len(), 1usize); + assert_eq!(traces.first().unwrap().receipt.global_sequence, 10128941153u64); +} + #[test] fn test_error_response_parsing() { let error_json = r#"{ @@ -225,7 +306,7 @@ fn test_error_response_parsing() { let error_response = parsed_error.expect("Failed to parse JSON"); assert_eq!( - error_response.error.code, 3050003, + error_response.error.code, Some(3050003), "Error code did not match" ); assert_eq!( diff --git a/crates/antelope/tests/utils/mock_provider.rs b/crates/antelope/tests/utils/mock_provider.rs index 3642757..4383bc7 100644 --- a/crates/antelope/tests/utils/mock_provider.rs +++ b/crates/antelope/tests/utils/mock_provider.rs @@ -53,7 +53,7 @@ impl Debug for MockProvider { #[async_trait::async_trait] impl Provider for MockProvider { - fn set_debug(&mut self, debug: bool) { + fn set_debug(&mut self, _debug: bool) { // TODO: Implement if we want debugging of the mock response in tests } From ce3b026fb61771da35dad4650089be45da948de3 Mon Sep 17 00:00:00 2001 From: Jesse Schulman Date: Thu, 10 Oct 2024 14:38:49 -0700 Subject: [PATCH 20/26] Formatting --- crates/antelope/src/api/v1/chain.rs | 5 ++++- crates/antelope/tests/client.rs | 14 ++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/crates/antelope/src/api/v1/chain.rs b/crates/antelope/src/api/v1/chain.rs index 9a529be..69da8d0 100644 --- a/crates/antelope/src/api/v1/chain.rs +++ b/crates/antelope/src/api/v1/chain.rs @@ -184,7 +184,10 @@ impl ChainAPI { Err(e) => { // If parsing the error response also fails, consider it an encoding error Err(ClientError::ENCODING(EncodingError { - message: format!("Failed to parse response: {} Raw response was: {}", e, result), + message: format!( + "Failed to parse response: {} Raw response was: {}", + e, result + ), })) } } diff --git a/crates/antelope/tests/client.rs b/crates/antelope/tests/client.rs index 9e5517d..90404b1 100644 --- a/crates/antelope/tests/client.rs +++ b/crates/antelope/tests/client.rs @@ -1,5 +1,7 @@ use antelope::api::client::DefaultProvider; -use antelope::api::v1::structs::{ErrorResponse, IndexPosition, SendTransactionResponse, TableIndexType}; +use antelope::api::v1::structs::{ + ErrorResponse, IndexPosition, SendTransactionResponse, TableIndexType, +}; use antelope::{ api::{ client::APIClient, @@ -267,13 +269,16 @@ fn test_send_transaction_response() { "error_code": null } }"#; - + let parsed = serde_json::from_str::(&response_json); assert!(parsed.is_ok()); let parsed = parsed.unwrap(); let traces = parsed.processed.action_traces; assert_eq!(traces.len(), 1usize); - assert_eq!(traces.first().unwrap().receipt.global_sequence, 10128941153u64); + assert_eq!( + traces.first().unwrap().receipt.global_sequence, + 10128941153u64 + ); } #[test] @@ -306,7 +311,8 @@ fn test_error_response_parsing() { let error_response = parsed_error.expect("Failed to parse JSON"); assert_eq!( - error_response.error.code, Some(3050003), + error_response.error.code, + Some(3050003), "Error code did not match" ); assert_eq!( From bdf2c318c5fcf7e05691b3d4336a34a406a7602c Mon Sep 17 00:00:00 2001 From: Paolo Tagliaferri Date: Mon, 14 Oct 2024 07:57:05 +0200 Subject: [PATCH 21/26] Trigger CI only on PR pushes In order to avoid duplicate runs, the trigger has now been set to activate when a new push within a PR targeting the `development` branch is detected. --- .github/workflows/on_push.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/on_push.yml b/.github/workflows/on_push.yml index 2875c7b..f1560d2 100644 --- a/.github/workflows/on_push.yml +++ b/.github/workflows/on_push.yml @@ -1,4 +1,6 @@ -on: [push, pull_request] +on: + pull_request: + branches: [ "development" ] name: Continuous integration From b82ec08a95c4311ce2ef06c3856964357f09d38a Mon Sep 17 00:00:00 2001 From: Paolo Tagliaferri Date: Mon, 14 Oct 2024 08:09:31 +0200 Subject: [PATCH 22/26] Added `--all-targets` as parameter of `cargo clippy` --- .github/workflows/on_push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/on_push.yml b/.github/workflows/on_push.yml index f1560d2..98688e2 100644 --- a/.github/workflows/on_push.yml +++ b/.github/workflows/on_push.yml @@ -63,4 +63,4 @@ jobs: - uses: actions-rs/cargo@v1 with: command: clippy - args: -- -D warnings + args: --all-targets -- -D warnings From c0b7ab2293d7e73c60c1ca4c53bd8a186442003b Mon Sep 17 00:00:00 2001 From: Paolo Tagliaferri Date: Mon, 14 Oct 2024 08:09:54 +0200 Subject: [PATCH 23/26] Fixed `cargo clippy` warnings --- crates/antelope/src/api/v1/structs.rs | 6 +++--- crates/antelope/tests/client.rs | 18 ++++-------------- crates/antelope/tests/utils/mock_provider.rs | 5 +++-- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/crates/antelope/src/api/v1/structs.rs b/crates/antelope/src/api/v1/structs.rs index 037d235..1835c30 100644 --- a/crates/antelope/src/api/v1/structs.rs +++ b/crates/antelope/src/api/v1/structs.rs @@ -1085,7 +1085,7 @@ mod tests { } "#; - let res = serde_json::from_str::(&simple_account_json).unwrap(); + let res = serde_json::from_str::(simple_account_json).unwrap(); println!("{:#?}", res); } @@ -1192,7 +1192,7 @@ mod tests { } "#; - let res = serde_json::from_str::(&detailed_account_json).unwrap(); + let res = serde_json::from_str::(detailed_account_json).unwrap(); println!("{:#?}", res); } @@ -1299,7 +1299,7 @@ mod tests { } "#; - let res = serde_json::from_str::(&detailed_account_json).unwrap(); + let res = serde_json::from_str::(detailed_account_json).unwrap(); println!("{:#?}", res); } } diff --git a/crates/antelope/tests/client.rs b/crates/antelope/tests/client.rs index 90404b1..800ed6a 100644 --- a/crates/antelope/tests/client.rs +++ b/crates/antelope/tests/client.rs @@ -1,7 +1,4 @@ -use antelope::api::client::DefaultProvider; -use antelope::api::v1::structs::{ - ErrorResponse, IndexPosition, SendTransactionResponse, TableIndexType, -}; +use antelope::api::v1::structs::{ErrorResponse, SendTransactionResponse}; use antelope::{ api::{ client::APIClient, @@ -122,15 +119,8 @@ async fn chain_send_transaction() { let failure_response = failed_result.err().unwrap(); println!("{:?}", failure_response); match failure_response { - ClientError::SERVER(err) => { - assert_eq!(err.error.code, Some(3050003)); - } - _ => { - assert!( - false, - "Failure response should be of type ClientError::SERVER" - ) - } + ClientError::SERVER(err) => assert_eq!(err.error.code, Some(3050003)), + _ => panic!("Failure response should be of type ClientError::SERVER"), } } @@ -270,7 +260,7 @@ fn test_send_transaction_response() { } }"#; - let parsed = serde_json::from_str::(&response_json); + let parsed = serde_json::from_str::(response_json); assert!(parsed.is_ok()); let parsed = parsed.unwrap(); let traces = parsed.processed.action_traces; diff --git a/crates/antelope/tests/utils/mock_provider.rs b/crates/antelope/tests/utils/mock_provider.rs index 4383bc7..ef10ecd 100644 --- a/crates/antelope/tests/utils/mock_provider.rs +++ b/crates/antelope/tests/utils/mock_provider.rs @@ -33,8 +33,9 @@ impl MockProvider { body: Option, ) -> Result { let mut to_hash = method.to_string() + &path; - if body.is_some() { - to_hash += body.unwrap().as_str(); + + if let Some(body) = body { + to_hash += body.as_str(); } let filename = Checksum160::hash(to_hash.into_bytes()).to_string(); From 84ef2249471ff5f808c689000cf711185c9a059d Mon Sep 17 00:00:00 2001 From: lesa-telos Date: Tue, 15 Oct 2024 16:18:16 +0200 Subject: [PATCH 24/26] Finish table rows params fix logging (#37) * Changes for ship reading * Adding support for other index types on next_key * Fix ABI encoding, better handle secondary index table queries * WIP - Complete GetTableRowsParams to_json functionality * Switch endian order for Checksum256 index, only works for rscdk compiled contracts * Some changes to deseralize blocks * Disable TrxVarient on get block response for now * Fix mock provider data * formatter and clippy pass * Partially revert "Switch endian order for Checksum256 index, only works for rscdk compiled contracts" This reverts commit 6977b8bc126e5fac75c6305f81889a573a3d3a73, in particular the endianness of Checksum256. This is needed to be compatible with the C++ smart contracts compiler, while rscdk (Rust WASM compiler) needs the commit that here is being reverted. This means that going on antelope-rs will be compatible with the C++ smart contracts compiler and not with the Rust compiler. * Removed `secondary_index` test The test was meant to check the consistency of the Checksum256 encoding with the SNARKtor contracts and the WASM-compiled smart contracts in general. However, given that the `rscdk` compiler treats the encoding of Checksum256 with a different encoding compared to the C++ compiler, the test has been removed. It could be restored once the `rscdk` issue is fixed. * Removed commented code * Add tracing logging instead of println. * Remove debug flag. * fmt. * Rollback default provided implementation. * Remove prints for the tests. * Fix compile after merge. --------- Co-authored-by: Jesse Schulman Co-authored-by: Guillermo Rodriguez Co-authored-by: Paolo Tagliaferri Co-authored-by: lesa-telos --- Cargo.lock | 13 ++++++ crates/antelope/Cargo.toml | 1 + crates/antelope/src/api/client.rs | 13 +----- crates/antelope/src/api/default_provider.rs | 43 ++++---------------- crates/antelope/src/api/system/mod.rs | 3 +- crates/antelope/src/api/v1/structs.rs | 3 +- crates/antelope/src/crypto/sign.rs | 12 +++--- crates/antelope/tests/chain.rs | 31 +++++--------- crates/antelope/tests/client.rs | 11 +---- crates/antelope/tests/serializer.rs | 6 +-- crates/antelope/tests/utils/mock_provider.rs | 4 -- 11 files changed, 47 insertions(+), 93 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9ae4e44..23e1647 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,6 +61,7 @@ dependencies = [ "signature", "thiserror", "tokio", + "tracing", ] [[package]] @@ -1431,9 +1432,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + [[package]] name = "tracing-core" version = "0.1.32" diff --git a/crates/antelope/Cargo.toml b/crates/antelope/Cargo.toml index 54dd346..052c17d 100644 --- a/crates/antelope/Cargo.toml +++ b/crates/antelope/Cargo.toml @@ -45,3 +45,4 @@ hmac = "0.12.1" rand_core = "0.6.4" async-trait = "0.1.77" thiserror = "1.0.57" +tracing = "0.1.40" \ No newline at end of file diff --git a/crates/antelope/src/api/client.rs b/crates/antelope/src/api/client.rs index 32609e7..8e6ea4a 100644 --- a/crates/antelope/src/api/client.rs +++ b/crates/antelope/src/api/client.rs @@ -29,7 +29,6 @@ impl Display for HTTPMethod { #[async_trait::async_trait] pub trait Provider: Debug + Default + Sync + Send { - fn set_debug(&mut self, debug: bool); async fn post(&self, path: String, body: Option) -> Result; async fn get(&self, path: String) -> Result; } @@ -44,17 +43,7 @@ impl APIClient

{ base_url: String, timeout: Option, ) -> Result, String> { - Self::default_provider_debug(base_url, timeout, false) - } - - pub fn default_provider_debug( - base_url: String, - timeout: Option, - debug: bool, - ) -> Result, String> { - let mut provider = DefaultProvider::new(base_url, timeout).unwrap(); - provider.set_debug(debug); - + let provider = DefaultProvider::new(base_url, timeout)?; APIClient::custom_provider(provider) } diff --git a/crates/antelope/src/api/default_provider.rs b/crates/antelope/src/api/default_provider.rs index 9d4a8ae..42d2140 100644 --- a/crates/antelope/src/api/default_provider.rs +++ b/crates/antelope/src/api/default_provider.rs @@ -1,12 +1,10 @@ -use std::fmt::{Debug, Formatter}; - -use reqwest::Client; - use crate::api::client::Provider; +use reqwest::Client; +use std::fmt::{Debug, Formatter}; +use tracing::debug; #[derive(Default, Clone)] pub struct DefaultProvider { - debug: bool, base_url: String, client: Client, } @@ -31,7 +29,6 @@ impl DefaultProvider { let url = base_url.trim_end_matches('/'); Ok(Self { - debug: false, base_url: String::from(url), client: client.unwrap(), }) @@ -47,10 +44,7 @@ impl Debug for DefaultProvider { #[async_trait::async_trait] impl Provider for DefaultProvider { async fn get(&self, path: String) -> Result { - if self.debug { - println!("GET {}", self.base_url.to_string() + &path); - } - + debug!("GET {}", self.base_url.to_string() + &path); let res = self .client .get(self.base_url.to_string() + &path) @@ -58,18 +52,12 @@ impl Provider for DefaultProvider { .await; if res.is_err() { let res_err = res.err().unwrap().to_string(); - if self.debug { - println!("Error: {}", res_err); - } - + debug!("Error: {}", res_err); return Err(res_err); } let response = res.unwrap().text().await.unwrap(); - if self.debug { - println!("Response: {}", response); - } - + debug!("Response: {}", response); Ok(response) } @@ -77,31 +65,18 @@ impl Provider for DefaultProvider { let mut builder = self.client.post(self.base_url.to_string() + &path); if body.is_some() { let body_str = body.unwrap(); - if self.debug { - println!("POST {} {}", self.base_url.to_string() + &path, body_str); - } - + debug!("POST {} {}", self.base_url.to_string() + &path, body_str); builder = builder.body(body_str); } let res = builder.send().await; if res.is_err() { let err_str = res.err().unwrap().to_string(); - if self.debug { - println!("Error: {}", err_str); - } - + debug!("Error: {}", err_str); return Err(err_str); } let response = res.unwrap().text().await.unwrap(); - if self.debug { - println!("Response: {}", response); - } - + debug!("Response: {}", response); Ok(response) } - - fn set_debug(&mut self, debug: bool) { - self.debug = debug; - } } diff --git a/crates/antelope/src/api/system/mod.rs b/crates/antelope/src/api/system/mod.rs index 3eaed89..185127a 100644 --- a/crates/antelope/src/api/system/mod.rs +++ b/crates/antelope/src/api/system/mod.rs @@ -15,6 +15,7 @@ use crate::name; use crate::serializer::Encoder; use sha2::{Digest, Sha256}; use std::path::Path; +use tracing::info; #[derive(Debug, Default, Clone)] pub struct SystemAPI { @@ -124,7 +125,7 @@ impl SystemAPI { let mut hasher = Sha256::new(); hasher.update(&wasm); let wasm_hash = hasher.finalize(); - println!( + info!( "Setting contract for account: {:?}, with hash: {:?}", account.as_string(), wasm_hash diff --git a/crates/antelope/src/api/v1/structs.rs b/crates/antelope/src/api/v1/structs.rs index 1835c30..a789c53 100644 --- a/crates/antelope/src/api/v1/structs.rs +++ b/crates/antelope/src/api/v1/structs.rs @@ -21,6 +21,7 @@ use crate::chain::{ transaction::TransactionHeader, varint::VarUint32, }; +use tracing::info; #[derive(Debug)] pub enum ClientError { @@ -200,7 +201,7 @@ pub struct SendTransactionResponseError { impl SendTransactionResponseError { pub fn print_error(&self) { - self.details.iter().for_each(|d| println!("{:?}", d)); + self.details.iter().for_each(|d| info!("{:?}", d)); } pub fn get_stack(&self) -> String { diff --git a/crates/antelope/src/crypto/sign.rs b/crates/antelope/src/crypto/sign.rs index 430b50c..f9f7b07 100644 --- a/crates/antelope/src/crypto/sign.rs +++ b/crates/antelope/src/crypto/sign.rs @@ -1,3 +1,7 @@ +use crate::{ + chain::{key_type::KeyType, signature::Signature}, + crypto::curves::{create_k1_field_bytes, create_r1_field_bytes}, +}; use digest::{ consts::U32, core_api::{CoreWrapper, CtVariableCoreWrapper}, @@ -12,11 +16,7 @@ use k256::{ecdsa::signature::DigestSigner, Secp256k1}; use p256::NistP256; use sha2::{Digest, OidSha256, Sha256, Sha256VarCore}; use signature::Error; - -use crate::{ - chain::{key_type::KeyType, signature::Signature}, - crypto::curves::{create_k1_field_bytes, create_r1_field_bytes}, -}; +use tracing::info; pub fn sign(secret: Vec, message: &Vec, key_type: KeyType) -> Result { match key_type { @@ -43,7 +43,7 @@ pub fn sign(secret: Vec, message: &Vec, key_type: KeyType) -> Result 100 { diff --git a/crates/antelope/tests/chain.rs b/crates/antelope/tests/chain.rs index 9643394..480207c 100644 --- a/crates/antelope/tests/chain.rs +++ b/crates/antelope/tests/chain.rs @@ -104,23 +104,12 @@ fn asset() { fn block_id() { let string = "048865fb643bca3b644647177f0cf363f7956794d0a7ec3bc6d29d93d9637308"; - let block_id = match hex::decode(string) { - Ok(bytes) => match BlockId::from_bytes(&bytes) { - Ok(block_id) => block_id, - Err(err) => { - eprintln!("Error creating BlockId: {}", err); - return; - } - }, - Err(err) => { - eprintln!("Error decoding hex string: {}", err); - return; - } - }; + let block_id_bytes = hex::decode(string).unwrap(); + let block_id = BlockId::from_bytes(&block_id_bytes).unwrap(); - //assert_eq!(block_id.to_string(), string); assert_eq!(block_id.block_num().to_string(), "76047867"); - assert!(block_id.block_num() == 76047867); + assert_eq!(block_id.block_num(), 76047867); + //assert!(block_id.block_num().equals(UInt32::from(76047867))); UInt32 not // implemented yet @@ -420,13 +409,13 @@ fn transaction() { */ // fn print_values(perm: &PermissionLevel, other_perm: &PermissionLevel) { -// println!("------Testing to_string()------"); -// println!("Permission 1: {}", perm.to_string()); -// println!("Permission 2: {}", other_perm.to_string()); +// info!("------Testing to_string()------"); +// info!("Permission 1: {}", perm.to_string()); +// info!("Permission 2: {}", other_perm.to_string()); -// println!("--------Testing json()--------"); -// println!("Permission 1: {:?}", perm.to_json()); -// println!("Permission 2: {:?}", other_perm.to_json()); +// info!("--------Testing json()--------"); +// info!("Permission 1: {:?}", perm.to_json()); +// info!("Permission 2: {:?}", other_perm.to_json()); // } #[test] diff --git a/crates/antelope/tests/client.rs b/crates/antelope/tests/client.rs index 800ed6a..1dad4c5 100644 --- a/crates/antelope/tests/client.rs +++ b/crates/antelope/tests/client.rs @@ -22,9 +22,6 @@ async fn chain_get_info() { let result = client.v1_chain.get_info().await; - if let Err(e) = &result { - println!("Deserialization error: {:?}", e); - } assert!(result.is_ok()); let result_unwrapped = result.unwrap(); @@ -117,7 +114,7 @@ async fn chain_send_transaction() { "Failed transaction result should be err" ); let failure_response = failed_result.err().unwrap(); - println!("{:?}", failure_response); + match failure_response { ClientError::SERVER(err) => assert_eq!(err.error.code, Some(3050003)), _ => panic!("Failure response should be of type ClientError::SERVER"), @@ -147,8 +144,7 @@ async fn chan_get_account() { } Err(e) => { // Log or handle errors here to understand parsing issues - println!("Failed to parse JSON: {:?}", e); - panic!("Parsing failed for the given JSON data."); + panic!("Failed to parse JSON: {:?}", e); } } } @@ -160,9 +156,6 @@ pub async fn chain_get_abi() { let result = client.v1_chain.get_abi("eosio.token".to_string()).await; - if let Err(e) = &result { - println!("Deserialization error: {:?}", e); - } assert!(result.is_ok()); let abi_object = result.unwrap(); diff --git a/crates/antelope/tests/serializer.rs b/crates/antelope/tests/serializer.rs index b71d717..8b0943c 100644 --- a/crates/antelope/tests/serializer.rs +++ b/crates/antelope/tests/serializer.rs @@ -1150,11 +1150,7 @@ fn setcode() { hasher.update(&wasm); let wasm_hash = hasher.finalize(); let wasm_hash_hex = bytes_to_hex(&wasm_hash.to_vec()); - println!( - "Setting contract for account: {:?}, with hash: {:?}", - account.as_string(), - wasm_hash_hex - ); + assert_eq!( wasm_hash_hex, "295586a9f3b2de36d637dbde251106cee7b23d3fd1e4d0162df43c3bbaa6e800" diff --git a/crates/antelope/tests/utils/mock_provider.rs b/crates/antelope/tests/utils/mock_provider.rs index ef10ecd..00034d9 100644 --- a/crates/antelope/tests/utils/mock_provider.rs +++ b/crates/antelope/tests/utils/mock_provider.rs @@ -54,10 +54,6 @@ impl Debug for MockProvider { #[async_trait::async_trait] impl Provider for MockProvider { - fn set_debug(&mut self, _debug: bool) { - // TODO: Implement if we want debugging of the mock response in tests - } - async fn post(&self, path: String, body: Option) -> Result { self.call(HTTPMethod::POST, path, body) } From 4ea9bf182713d772eb765b741b6f2cd55f6e1db5 Mon Sep 17 00:00:00 2001 From: Jesse Schulman Date: Tue, 15 Oct 2024 11:07:29 -0700 Subject: [PATCH 25/26] Bump version --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dfae43b..9d638f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ members = [ ] [workspace.package] -version = "0.2.1" +version = "0.3.0" edition = "2021" rust-version = "1.75" authors = ["Jesse Schulman "] @@ -14,4 +14,4 @@ license = "MIT OR Apache-2.0" homepage = "https://github.com/telosnetwork/antelope-rs" repository = "https://github.com/telosnetwork/antelope-rs" keywords = ["blockchain", "antelope"] -categories = ["cryptography::cryptocurrencies", "encoding"] \ No newline at end of file +categories = ["cryptography::cryptocurrencies", "encoding"] From 2aabfaba9a0a248c5c10107f4f33412be6715a3a Mon Sep 17 00:00:00 2001 From: Jesse Schulman Date: Tue, 15 Oct 2024 11:15:09 -0700 Subject: [PATCH 26/26] Run CI on all pull_requests --- .github/workflows/{on_push.yml => on_pull_request.yml} | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) rename .github/workflows/{on_push.yml => on_pull_request.yml} (96%) diff --git a/.github/workflows/on_push.yml b/.github/workflows/on_pull_request.yml similarity index 96% rename from .github/workflows/on_push.yml rename to .github/workflows/on_pull_request.yml index 98688e2..b60967b 100644 --- a/.github/workflows/on_push.yml +++ b/.github/workflows/on_pull_request.yml @@ -1,6 +1,4 @@ -on: - pull_request: - branches: [ "development" ] +on: [pull_request] name: Continuous integration