Skip to content

Commit

Permalink
sui-graphql-client: add transaction effects query (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
stefan-mysten authored Nov 13, 2024
1 parent 4aa79e6 commit 98ecfa1
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 4 deletions.
100 changes: 99 additions & 1 deletion crates/sui-graphql-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ use query_types::ResolveSuinsQueryArgs;
use query_types::ServiceConfig;
use query_types::ServiceConfigQuery;
use query_types::TransactionBlockArgs;
use query_types::TransactionBlockEffectsQuery;
use query_types::TransactionBlockQuery;
use query_types::TransactionBlocksEffectsQuery;
use query_types::TransactionBlocksQuery;
use query_types::TransactionBlocksQueryArgs;
use query_types::TransactionMetadata;
Expand All @@ -85,6 +87,7 @@ use sui_types::types::MovePackage;
use sui_types::types::Object;
use sui_types::types::SignedTransaction;
use sui_types::types::Transaction;
use sui_types::types::TransactionDigest;
use sui_types::types::TransactionEffects;
use sui_types::types::TransactionKind;
use sui_types::types::TypeTag;
Expand Down Expand Up @@ -1482,6 +1485,24 @@ impl Client {
.map_err(|e| Error::msg(format!("Cannot decode transaction: {e}")))
}

/// Get a transaction's effects by its digest.
pub async fn transaction_effects(
&self,
digest: TransactionDigest,
) -> Result<Option<TransactionEffects>, Error> {
let operation = TransactionBlockEffectsQuery::build(TransactionBlockArgs {
digest: digest.to_string(),
});
let response = self.run_query(&operation).await?;

response
.data
.and_then(|d| d.transaction_block)
.map(|tx| tx.try_into())
.transpose()
.map_err(|e| Error::msg(format!("Cannot decode transaction: {e}")))
}

/// Get a page of transactions based on the provided filters.
pub async fn transactions<'a>(
&self,
Expand Down Expand Up @@ -1516,6 +1537,40 @@ impl Client {
}
}

/// Get a page of transactions' effects based on the provided filters.
pub async fn transactions_effects<'a>(
&self,
filter: Option<TransactionsFilter<'a>>,
pagination_filter: PaginationFilter,
) -> Result<Page<TransactionEffects>, Error> {
let (after, before, first, last) = self.pagination_filter(pagination_filter).await;

let operation = TransactionBlocksEffectsQuery::build(TransactionBlocksQueryArgs {
after: after.as_deref(),
before: before.as_deref(),
filter,
first,
last,
});

let response = self.run_query(&operation).await?;

if let Some(txb) = response.data {
let txc = txb.transaction_blocks;
let page_info = txc.page_info;

let transactions = txc
.nodes
.into_iter()
.map(|n| n.try_into())
.collect::<Result<Vec<_>>>()?;
let page = Page::new(page_info, transactions);
Ok(page)
} else {
Ok(Page::new_empty())
}
}

/// Get a stream of transactions based on the (optional) transaction filter.
pub async fn transactions_stream<'a>(
&'a self,
Expand All @@ -1528,6 +1583,18 @@ impl Client {
)
}

/// Get a stream of transactions' effects based on the (optional) transaction filter.
pub async fn transactions_effects_stream<'a>(
&'a self,
filter: Option<TransactionsFilter<'a>>,
streaming_direction: Direction,
) -> impl Stream<Item = Result<TransactionEffects, Error>> + 'a {
stream_paginated_query(
move |pag_filter| self.transactions_effects(filter.clone(), pag_filter),
streaming_direction,
)
}

/// Execute a transaction.
pub async fn execute_tx(
&self,
Expand Down Expand Up @@ -1695,6 +1762,8 @@ mod tests {
use crate::MAINNET_HOST;
use crate::TESTNET_HOST;

const NUM_COINS_FROM_FAUCET: usize = 5;

fn test_client() -> Client {
let network = std::env::var("NETWORK").unwrap_or_else(|_| "local".to_string());
match network.as_str() {
Expand Down Expand Up @@ -1953,7 +2022,6 @@ mod tests {

#[tokio::test]
async fn test_coins_stream() {
const NUM_COINS_FROM_FAUCET: usize = 5;
let client = test_client();
let faucet = match client.rpc_server() {
LOCAL_HOST => FaucetClient::local(),
Expand All @@ -1976,6 +2044,36 @@ mod tests {
assert!(num_coins == NUM_COINS_FROM_FAUCET);
}

#[tokio::test]
async fn test_transaction_effects_query() {
let client = test_client();
let transactions = client
.transactions(None, PaginationFilter::default())
.await
.unwrap();
let tx_digest = transactions.data()[0].transaction.digest();
let effects = client.transaction_effects(tx_digest).await.unwrap();
assert!(
effects.is_some(),
"Transaction effects query failed for {} network.",
client.rpc_server(),
);
}

#[tokio::test]
async fn test_transactions_effects_query() {
let client = test_client();
let txs_effects = client
.transactions_effects(None, PaginationFilter::default())
.await;
assert!(
txs_effects.is_ok(),
"Transactions effects query failed for {} network. Error: {}",
client.rpc_server(),
txs_effects.unwrap_err()
);
}

#[tokio::test]
async fn test_transactions_query() {
let client = test_client();
Expand Down
5 changes: 3 additions & 2 deletions crates/sui-graphql-client/src/query_types/dry_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use sui_types::types::ObjectReference;

use crate::query_types::schema;
use crate::query_types::Address;
use crate::query_types::TransactionBlock;

use super::transaction::TxBlockEffects;

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "Query", variables = "DryRunArgs")]
Expand All @@ -18,7 +19,7 @@ pub struct DryRunQuery {
#[cynic(schema = "rpc", graphql_type = "DryRunResult")]
pub struct DryRunResult {
pub error: Option<String>,
pub transaction: Option<TransactionBlock>,
pub transaction: Option<TxBlockEffects>,
}

#[derive(cynic::QueryVariables, Debug)]
Expand Down
2 changes: 2 additions & 0 deletions crates/sui-graphql-client/src/query_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ pub use suins::ResolveSuinsQuery;
pub use suins::ResolveSuinsQueryArgs;
pub use transaction::TransactionBlock;
pub use transaction::TransactionBlockArgs;
pub use transaction::TransactionBlockEffectsQuery;
pub use transaction::TransactionBlockQuery;
pub use transaction::TransactionBlocksEffectsQuery;
pub use transaction::TransactionBlocksQuery;
pub use transaction::TransactionBlocksQueryArgs;
pub use transaction::TransactionsFilter;
Expand Down
52 changes: 51 additions & 1 deletion crates/sui-graphql-client/src/query_types/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use anyhow::Error;
use base64ct::Encoding;
use sui_types::types::SignedTransaction;
use sui_types::types::Transaction;
use sui_types::types::TransactionEffects;
use sui_types::types::UserSignature;

use crate::query_types::schema;
Expand All @@ -27,6 +28,17 @@ pub struct TransactionBlockQuery {
pub transaction_block: Option<TransactionBlock>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(
schema = "rpc",
graphql_type = "Query",
variables = "TransactionBlockArgs"
)]
pub struct TransactionBlockEffectsQuery {
#[arguments(digest: $digest)]
pub transaction_block: Option<TxBlockEffects>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(
schema = "rpc",
Expand All @@ -38,6 +50,16 @@ pub struct TransactionBlocksQuery {
pub transaction_blocks: TransactionBlockConnection,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(
schema = "rpc",
graphql_type = "Query",
variables = "TransactionBlocksQueryArgs"
)]
pub struct TransactionBlocksEffectsQuery {
#[arguments(first: $first, after: $after, last: $last, before: $before, filter: $filter)]
pub transaction_blocks: TransactionBlockEffectsConnection,
}
// ===========================================================================
// Transaction Block(s) Query Args
// ===========================================================================
Expand All @@ -64,10 +86,15 @@ pub struct TransactionBlocksQueryArgs<'a> {
#[cynic(schema = "rpc", graphql_type = "TransactionBlock")]
pub struct TransactionBlock {
pub bcs: Option<Base64>,
pub effects: Option<TransactionBlockEffects>,
pub signatures: Option<Vec<Base64>>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "TransactionBlock")]
pub struct TxBlockEffects {
pub effects: Option<TransactionBlockEffects>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "TransactionBlockEffects")]
pub struct TransactionBlockEffects {
Expand Down Expand Up @@ -107,6 +134,13 @@ pub struct TransactionBlockConnection {
pub page_info: PageInfo,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(schema = "rpc", graphql_type = "TransactionBlockConnection")]
pub struct TransactionBlockEffectsConnection {
pub nodes: Vec<TxBlockEffects>,
pub page_info: PageInfo,
}

impl TryFrom<TransactionBlock> for SignedTransaction {
type Error = anyhow::Error;

Expand Down Expand Up @@ -139,3 +173,19 @@ impl TryFrom<TransactionBlock> for SignedTransaction {
}
}
}

impl TryFrom<TxBlockEffects> for TransactionEffects {
type Error = anyhow::Error;

fn try_from(value: TxBlockEffects) -> Result<Self, Self::Error> {
let effects = value
.effects
.map(|fx| base64ct::Base64::decode_vec(fx.bcs.unwrap().0.as_str()))
.transpose()
.map_err(|_| Error::msg("Cannot decode Base64 effects bcs bytes"))?
.map(|bcs| bcs::from_bytes::<TransactionEffects>(&bcs))
.transpose()
.map_err(|_| Error::msg("Cannot decode bcs bytes into TransactionEffects"))?;
effects.ok_or_else(|| Error::msg("Cannot decode effects"))
}
}

0 comments on commit 98ecfa1

Please sign in to comment.