iota_graphql_rpc/mutation.rs
1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4use async_graphql::*;
5use fastcrypto::encoding::Base64;
6
7use crate::{
8 error::Error,
9 server::builder::get_write_api,
10 types::{
11 execution_result::ExecutionResult, transaction_block_effects::TransactionBlockEffects,
12 },
13};
14pub struct Mutation;
15
16/// Mutations are used to write to the IOTA network.
17#[Object]
18impl Mutation {
19 /// Execute a transaction, committing its effects on chain.
20 ///
21 /// - `txBytes` is a `TransactionData` struct that has been BCS-encoded and
22 /// then Base64-encoded.
23 /// - `signatures` are a list of `flag || signature || pubkey` bytes,
24 /// Base64-encoded.
25 ///
26 /// Waits until the transaction has reached finality on chain to return its
27 /// transaction digest, or returns the error that prevented finality if
28 /// that was not possible. A transaction is final when its effects are
29 /// guaranteed on chain (it cannot be revoked).
30 ///
31 /// Transaction effects are now available immediately after execution
32 /// through `Query.transactionBlock`. However, other queries that depend
33 /// on the chain’s indexed state (e.g., address-level balance updates)
34 /// may still lag until the transaction has been checkpointed.
35 /// To confirm that a transaction has been included in a checkpoint, query
36 /// `Query.transactionBlock` and check whether the `effects.checkpoint`
37 /// field is set (or `null` if not yet checkpointed).
38 async fn execute_transaction_block(
39 &self,
40 ctx: &Context<'_>,
41 tx_bytes: String,
42 signatures: Vec<String>,
43 ) -> Result<ExecutionResult> {
44 let write_api = get_write_api(ctx).extend()?;
45 let tx_data = Base64::try_from(tx_bytes)
46 .map_err(|e| {
47 Error::Client(format!(
48 "Unable to deserialize transaction bytes from Base64: {e}"
49 ))
50 })
51 .extend()?;
52
53 let mut sigs = Vec::new();
54 for sig in signatures {
55 sigs.push(
56 Base64::try_from(sig.clone())
57 .map_err(|e| {
58 Error::Client(format!(
59 "Unable to deserialize signature bytes {sig} from Base64: {e}"
60 ))
61 })
62 .extend()?,
63 );
64 }
65 let ingestion_path = write_api
66 .executor()
67 .execute_and_index_transaction(tx_data, sigs)
68 .await
69 .map_err(|e| Error::Internal(format!("Unable to execute transaction: {e}")))
70 .extend()?;
71
72 let effects = TransactionBlockEffects::try_from(ingestion_path).extend()?;
73
74 Ok(ExecutionResult {
75 errors: effects.errors(ctx).await?.map(|e| vec![e]),
76 effects,
77 })
78 }
79}