Skip to main content

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}