Skip to content

Commit

Permalink
Implement send_transaction2
Browse files Browse the repository at this point in the history
  • Loading branch information
coa-telos committed Dec 4, 2024
1 parent 013e56a commit 7d6c4cb
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 10 deletions.
68 changes: 61 additions & 7 deletions crates/antelope/src/api/v1/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ use std::fmt::Debug;
use serde_json::{self, Value};

use crate::api::v1::structs::{
ABIResponse, EncodingError, GetBlockResponse, GetTransactionStatusResponse, ServerError,
ABIResponse, EncodingError, GetBlockResponse, GetTransactionStatusResponse,
SendTransaction2Request, ServerError,
};
use crate::chain::checksum::{Checksum160, Checksum256};
use crate::{
api::{
client::Provider,
v1::structs::{
AccountObject, ClientError, ErrorResponse, GetInfoResponse, GetTableRowsParams,
GetTableRowsResponse, SendTransactionResponse, SendTransactionResponseError,
TableIndexType,
AccountObject, ClientError, ErrorResponse, ErrorResponse2, GetInfoResponse,
GetTableRowsParams, GetTableRowsResponse, SendTransaction2Options,
SendTransaction2Response, SendTransactionResponse, SendTransactionResponse2Error,
SendTransactionResponseError, TableIndexType,
},
},
chain::{
Expand All @@ -35,8 +37,6 @@ impl<T: Provider> ChainAPI<T> {
ChainAPI { provider }
}

// pub async fn get_abi(&self) -> Result<

pub async fn get_account(
&self,
account_name: String,
Expand Down Expand Up @@ -155,6 +155,8 @@ impl<T: Provider> ChainAPI<T> {
}
}

/// send_transaction sends transaction to telos using /v1/chain/send_transaction
/// and using ZLIB compression type.
pub async fn send_transaction(
&self,
trx: SignedTransaction,
Expand All @@ -165,7 +167,10 @@ impl<T: Provider> ChainAPI<T> {
let trx_json = packed.to_json();
let result = self
.provider
.post(String::from("/v1/chain/send_transaction"), Some(trx_json))
.post(
String::from("/v1/chain/send_transaction"),
Some(trx_json.to_string()),
)
.await
.map_err(|_| ClientError::NETWORK("Failed to send transaction".into()))?;

Expand Down Expand Up @@ -195,6 +200,55 @@ impl<T: Provider> ChainAPI<T> {
}
}

/// send_transaction2 sends transaction to telos using /v1/chain/send_transaction2
/// which enables retry in case of transaction failure using ZLIB compression type.
pub async fn send_transaction2(
&self,
trx: SignedTransaction,
options: Option<SendTransaction2Options>,
) -> Result<SendTransaction2Response, ClientError<SendTransactionResponse2Error>> {
let packed_transaction = PackedTransaction::from_signed(trx, CompressionType::ZLIB)
.map_err(|_| ClientError::encoding("Failed to pack transaction".into()))?;

let request_body = SendTransaction2Request::build(packed_transaction, options);

let request_body_str = serde_json::to_string(&request_body)
.map_err(|_| ClientError::encoding("Failed to serialize request body".into()))?;

// Send the request to the endpoint
let result = self
.provider
.post(
String::from("/v1/chain/send_transaction2"),
Some(request_body_str),
)
.await
.map_err(|_| ClientError::NETWORK("Failed to send transaction".into()))?;

// tracing::warn!("Result of the send_transaction2: {result}");

// Deserialize the response
match serde_json::from_str::<SendTransaction2Response>(&result) {
Ok(response) => match response.processed.except {
Some(error) => Err(ClientError::SERVER(ServerError { error })),
None => Ok(response),
},
Err(error) => {
tracing::error!("Failed to deserialize send_transactions2 response: {error}");

// Try to parse an error response
match serde_json::from_str::<ErrorResponse2>(&result) {
Ok(error_response) => Err(ClientError::SERVER(ServerError {
error: error_response.error,
})),
Err(e) => Err(ClientError::ENCODING(EncodingError {
message: format!("Failed to parse response: {}", e),
})),
}
}
}
}

pub async fn get_transaction_status(
&self,
trx_id: Checksum256,
Expand Down
74 changes: 73 additions & 1 deletion crates/antelope/src/api/v1/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::mem::discriminant;
use crate::chain::abi::ABI;
use crate::chain::public_key::PublicKey;
use crate::chain::signature::Signature;
use crate::chain::transaction::PackedTransaction;
use crate::chain::{
action::{Action, PermissionLevel},
asset::{deserialize_asset, deserialize_optional_asset, Asset},
Expand Down Expand Up @@ -172,6 +173,22 @@ pub struct ProcessedTransaction {
pub account_ram_delta: Option<AccountRamDelta>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ProcessedTransaction2 {
pub id: String,
pub block_num: u64,
pub block_time: String,
pub producer_block_id: Option<String>,
pub receipt: Option<ProcessedTransactionReceipt>,
pub elapsed: u64,
pub net_usage: u32,
pub scheduled: bool,
pub action_traces: Vec<Value>,
pub account_ram_delta: Option<Value>,
pub except: Option<SendTransactionResponse2Error>,
pub error_code: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct SendTransactionResponseExceptionStackContext {
pub level: String,
Expand Down Expand Up @@ -199,6 +216,14 @@ pub struct SendTransactionResponseError {
pub details: Vec<SendTransactionResponseErrorDetails>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct SendTransactionResponse2Error {
pub code: Option<u32>,
pub name: String,
pub message: String,
pub stack: Option<Vec<Value>>,
}

impl SendTransactionResponseError {
pub fn print_error(&self) {
self.details.iter().for_each(|d| info!("{:?}", d));
Expand All @@ -225,20 +250,67 @@ pub struct SendTransactionResponseErrorDetails {
pub method: String,
}

pub struct SendTransaction2Options {
pub return_failure_trace: bool,
pub retry_trx: bool,
pub retry_trx_num_blocks: u32,
}

#[derive(Serialize)]
pub struct SendTransaction2Request {
pub return_failure_trace: bool,
pub retry_trx: bool,
pub retry_trx_num_blocks: u32,
pub transaction: Value,
}

impl SendTransaction2Request {
pub fn build(
trx: PackedTransaction,
options: Option<SendTransaction2Options>,
) -> SendTransaction2Request {
let opts = options.unwrap_or(SendTransaction2Options {
return_failure_trace: true,
retry_trx: false,
retry_trx_num_blocks: 0,
});

SendTransaction2Request {
return_failure_trace: opts.return_failure_trace,
retry_trx: opts.retry_trx,
retry_trx_num_blocks: opts.retry_trx_num_blocks,
transaction: trx.to_json(),
}
}
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ErrorResponse {
pub code: u16,
pub message: String,
pub error: SendTransactionResponseError,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ErrorResponse2 {
pub code: u16,
pub message: String,
pub error: SendTransactionResponse2Error,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct SendTransactionResponse {
pub transaction_id: String,
pub processed: ProcessedTransaction,
}

#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize)]
pub struct SendTransaction2Response {
pub transaction_id: String,
pub processed: ProcessedTransaction2,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum TransactionState {
LocallyApplied,
Expand Down
4 changes: 2 additions & 2 deletions crates/antelope/src/chain/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl PackedTransaction {
})
}

pub fn to_json(&self) -> String {
pub fn to_json(&self) -> Value {
let mut trx: HashMap<&str, Value> = HashMap::new();
let signatures: Vec<String> = self.signatures.iter().map(|sig| sig.to_string()).collect();
trx.insert("signatures", json!(signatures));
Expand All @@ -122,6 +122,6 @@ impl PackedTransaction {
"packed_trx",
Value::String(bytes_to_hex(&self.packed_transaction)),
);
json!(trx).to_string()
json!(trx)
}
}

0 comments on commit 7d6c4cb

Please sign in to comment.