Skip to content

Commit 23057e0

Browse files
committed
feat: added tx status, receipt and proof fetchers
1 parent c18d30b commit 23057e0

File tree

9 files changed

+568
-12
lines changed

9 files changed

+568
-12
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
[workspace]
22
resolver = "3"
33
members = ["api", "types"]
4-
rust-version = "1.85"
54

65
[workspace.package]
6+
rust-version = "1.85"
77
edition = "2024"
88
version = "0.8.3"
99
authors = [

api/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "near-api"
3-
rust-version = "1.85"
3+
rust-version.workspace = true
44
version.workspace = true
55
authors.workspace = true
66
license.workspace = true
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use near_api::{
2+
Chain, Transaction,
3+
types::{AccountId, CryptoHash, Reference, TxExecutionStatus},
4+
};
5+
use testresult::TestResult;
6+
7+
#[tokio::main]
8+
async fn main() -> TestResult {
9+
let sender: AccountId = "omni.bridge.near".parse()?;
10+
let tx_hash: CryptoHash = "GmvjRhbBwNCeekyZ4ezv43Zhs4U33kRTj6PRkFgKUKyJ".parse()?;
11+
12+
let status = Transaction::status(sender.clone(), tx_hash)
13+
.fetch_from_mainnet()
14+
.await?;
15+
println!(
16+
"[status] is_success={}, is_failure={}, gas_burnt={}",
17+
status.is_success(),
18+
status.is_failure(),
19+
status.total_gas_burnt,
20+
);
21+
22+
let status_final =
23+
Transaction::status_with_options(sender.clone(), tx_hash, TxExecutionStatus::Final)
24+
.fetch_from_mainnet()
25+
.await?;
26+
println!(
27+
"[status_with_options(Final)] is_success={}, receipts={}",
28+
status_final.is_success(),
29+
status_final.receipt_outcomes().len(),
30+
);
31+
32+
let receipt_id = status_final.outcome().receipt_ids[0];
33+
let receipt = Transaction::receipt(receipt_id)
34+
.fetch_from_mainnet()
35+
.await?;
36+
println!(
37+
"[receipt] id={}, receiver={}, predecessor={}",
38+
receipt.receipt_id, receipt.receiver_id, receipt.predecessor_id,
39+
);
40+
41+
let head_hash = Chain::block_hash()
42+
.at(Reference::Final)
43+
.fetch_from_mainnet()
44+
.await?;
45+
let proof = Transaction::proof(sender, tx_hash, head_hash)
46+
.fetch_from_mainnet()
47+
.await?;
48+
println!(
49+
"[proof] outcome_proof_id={}, block_proof_len={}, outcome_root_proof_len={}",
50+
proof.outcome_proof.id,
51+
proof.block_proof.len(),
52+
proof.outcome_root_proof.len(),
53+
);
54+
55+
println!("\nAll transaction query methods passed!");
56+
57+
Ok(())
58+
}

api/src/common/query/handlers/mod.rs

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
use borsh::BorshDeserialize;
22
use near_api_types::{
33
AccessKey, Account, AccountView, ContractCodeView, Data, PublicKey, RpcBlockResponse,
4-
RpcValidatorResponse, ViewStateResult, json::U64,
4+
RpcValidatorResponse, ViewStateResult, json::U64, transaction::result::ExecutionFinalResult,
5+
};
6+
use near_openapi_client::types::{
7+
FinalExecutionOutcomeView, RpcQueryResponse, RpcReceiptResponse, RpcTransactionResponse,
58
};
6-
use near_openapi_client::types::RpcQueryResponse;
79
use serde::de::DeserializeOwned;
810
use std::marker::PhantomData;
911
use tracing::{info, trace, warn};
1012

1113
use crate::{
1214
advanced::{
1315
RpcType, block_rpc::SimpleBlockRpc, query_rpc::SimpleQueryRpc,
14-
validator_rpc::SimpleValidatorRpc,
16+
tx_rpc::TransactionStatusRpc, validator_rpc::SimpleValidatorRpc,
1517
},
1618
common::query::{QUERY_EXECUTOR_TARGET, ResultWithMethod},
1719
errors::QueryError,
@@ -497,6 +499,93 @@ impl ResponseHandler for RpcBlockHandler {
497499
}
498500
}
499501

502+
/// Handler that converts an [`RpcTransactionResponse`] into an [`ExecutionFinalResult`].
503+
///
504+
/// This reuses the same conversion logic from transaction sending: it extracts the
505+
/// `FinalExecutionOutcomeView` from the response and converts it using `TryFrom`.
506+
#[derive(Clone, Debug)]
507+
pub struct TransactionStatusHandler;
508+
509+
impl ResponseHandler for TransactionStatusHandler {
510+
type Response = ExecutionFinalResult;
511+
type Query = TransactionStatusRpc;
512+
513+
fn process_response(
514+
&self,
515+
response: Vec<RpcTransactionResponse>,
516+
) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
517+
let response = response
518+
.into_iter()
519+
.next()
520+
.ok_or(QueryError::InternalErrorNoResponse)?;
521+
522+
let final_execution_outcome_view = match response {
523+
RpcTransactionResponse::Variant0 {
524+
final_execution_status: _,
525+
receipts: _,
526+
receipts_outcome,
527+
status,
528+
transaction,
529+
transaction_outcome,
530+
} => FinalExecutionOutcomeView {
531+
receipts_outcome,
532+
status,
533+
transaction,
534+
transaction_outcome,
535+
},
536+
RpcTransactionResponse::Variant1 {
537+
final_execution_status: _,
538+
receipts_outcome,
539+
status,
540+
transaction,
541+
transaction_outcome,
542+
} => FinalExecutionOutcomeView {
543+
receipts_outcome,
544+
status,
545+
transaction,
546+
transaction_outcome,
547+
},
548+
};
549+
550+
info!(
551+
target: QUERY_EXECUTOR_TARGET,
552+
"Processed TransactionStatus response, tx hash: {:?}",
553+
final_execution_outcome_view.transaction_outcome.id,
554+
);
555+
556+
ExecutionFinalResult::try_from(final_execution_outcome_view)
557+
.map_err(|e| QueryError::ConversionError(Box::new(e)))
558+
}
559+
}
560+
561+
/// Handler that passes through the raw [`RpcReceiptResponse`] without transformation.
562+
#[derive(Clone, Debug)]
563+
pub struct ReceiptHandler;
564+
565+
impl ResponseHandler for ReceiptHandler {
566+
type Response = RpcReceiptResponse;
567+
type Query = crate::advanced::tx_rpc::ReceiptRpc;
568+
569+
fn process_response(
570+
&self,
571+
response: Vec<RpcReceiptResponse>,
572+
) -> ResultWithMethod<Self::Response, <Self::Query as RpcType>::Error> {
573+
let response = response
574+
.into_iter()
575+
.next()
576+
.ok_or(QueryError::InternalErrorNoResponse)?;
577+
578+
info!(
579+
target: QUERY_EXECUTOR_TARGET,
580+
"Processed Receipt response, receipt_id: {:?}, receiver: {:?}",
581+
response.receipt_id,
582+
response.receiver_id,
583+
);
584+
585+
Ok(response)
586+
}
587+
}
588+
500589
impl<T: RpcType> ResponseHandler for T {
501590
type Response = <T as RpcType>::Response;
502591
type Query = T;

api/src/common/query/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub mod block_rpc;
1414
pub mod handlers;
1515
pub mod query_request;
1616
pub mod query_rpc;
17+
pub mod tx_rpc;
1718
pub mod validator_rpc;
1819

1920
pub use handlers::*;

0 commit comments

Comments
 (0)