Transactions
A transaction is a fundamental data structure for publishing a new program or a set of state transitions on the ledger. On Aleo, a transaction is issued locally by a user using their Aleo private key, which corresponds to an on-chain Aleo account. Using tools like Leo CLI, Provable SDK or ecosystem wallet adapters such as Puzzle Wallet SDK and Leo Wallet SDK.
Types of Transactions
Execute Transaction
The execution transaction represents a call to an Aleo program function. Below is the structure of an execution transaction response:
Parameter | Type | Description |
---|---|---|
type | string | The type of transaction (execute) |
id | string | The ID of transaction, computed via the Merkle Tree Digest of the transition IDs |
execution | object | The execution transaction info |
fee | object | The execution transaction fee |
Execution Object Info
Parameter | Type | Description |
---|---|---|
global_state_root | u16 | The global state root of the merkle tree |
transitions | array | The transitions |
proof | string | ZK proof of the execution |
Relationship of Transaction and Transition
- A Transaction is the top-level unit that represents a complete operation. A Transition is a lower-level component that represents an individual state change within a Transaction.
- A Transaction can contain multiple Transition objects. An Execution, which is part of a Transaction, includes a collection of Transitions.
- A Transaction may contain multiple Transitions, especially in cases involving multiple cross-program calls.
For more information of a Transition, please refer to Transitions.
Building an execution transaction using Leo CLI
Required Details:
- Program ID (name of deployed program)
- Function name to execute
- Arguments to the function
- Network ID (
testnet
ormainnet
) - Private key of the caller (or specify in .env from project directory)
Optional Parameters:
- Broadcast flag (to send to the network or not)
- Private fees
- Priority fees
Deploy Transaction
The deployment transaction publishes an Aleo program to the network.
Parameter | Type | Description |
---|---|---|
type | string | The type of transaction (deploy) |
id | string | The ID of transaction, computed via the Merkle Tree Digest of the transition IDs |
owner | object | The owner address and signature |
deployment | object | The deployment transaction info |
fee | object | The deployment transaction fee |
Deployment Object Info
Parameter | Type | Description |
---|---|---|
global_state_root | u16 | The global state root of the merkle tree |
transitions | array | The transitions |
Building a deployment transaction
Required Details:
- Compiled Leo program in Aleo Instructions
- Network ID (
testnet
ormainnet
) - Private key of the deployer (or specify in .env from project directory)
Optional Parameters:
- Private fees
- Priority fees
Fee Transaction
A fee transaction represents the network fee paid for processing. Rejected transactions are included in blocks as confirmed "rejected" transactions. In those cases, a new transaction ID is generated alongside a valid fee transaction to ensure the fee is charged. In normal successful execution case, the fee is recorded as a transition object within the execution or deployment transaction.
Parameter | Type | Description |
---|---|---|
type | string | The type of transaction (fee) |
id | string | The ID of transaction, computed via the Merkle Tree Digest of the transition IDs |
fee | object | The rejected transaction fee |
Transaction fees are calculated based on the size of the transaction and how complicated operations the validators need to do. Fees can be paid in public or private with Aleo Credits records. For more detailed information about transaction fees, please refer to Transaction Fees.
Transaction Lifecycle
Determining Transaction Status
Transactions processed by Aleo validators achieve one of the following states:
Status | Description |
---|---|
accepted | The underlying deployment or execution was successful, and the associated fee was consumed. The transaction has a confirmed ID. |
rejected | The deployment or execution logic failed. Validators process the fee as an independent fee transaction. The original transaction has an unconfirmed ID, while the fee transaction has a confirmed ID. |
aborted | Both the deployment/execution logic and fee processing failed. The transaction is aborted. |
Transactions may not be included in any block when not selected from the mempool by validators during high network load conditions.
Method 1: Parsing Transactions from Blocks
Transaction status can be determined by processing blocks retrieved via:
GET /<network>/block/{height}
- snarkOS node endpoint- Get block by height or hash on the Provable explorer
Transaction status can be determined from a block response as follows:
Accepted Transactions
- Get the list of transactions using
echo response | jq .transactions
- The transaction JSON contains
"status": "accepted"
- The transaction id is present in
echo transaction | jq .transaction.id
Rejected Transactions
- Get the list of transactions using
echo response | jq .transactions
- The transaction JSON contains
"status": "rejected"
- The confirmed transaction id is present in
echo transaction | jq .transaction.id
- The associated unconfirmed transaction id can be acquired by:
- Calling
GET /<network>/unconfirmed/{confirmed id}
and callingecho transaction | jq .transaction.id
- You can also hit
https://api.explorer.provable.com/v1/mainnet/transaction/unconfirmed/{ID}
- Calling
Aborted Transactions
- Get the list of aborted ids using
echo response | jq .aborted_transaction_ids
SDK - getConfirmedTransaction
import { AleoNetworkClient } from '@provablehq/sdk/mainnet.js';
const net = new AleoNetworkClient('https://api.explorer.provable.com/v1');
const txId = 'at14v8nt94d7xmsp3dq2glpzft6xw3x42ne753mlt8uenn8zw76dsqqc65jnf';
const status = await net.getConfirmedTransaction(txId);
console.log(status.status);
Method 2: Directly Querying Transaction Status
An alternative way to get feedback on the status of transactions, is to call the following endpoint.
GET /<network>/transaction/confirmed/{transaction id}
on a fully synced snarkOS node REST endpoint- Get transaction by ID on the Provable explorer
If the transaction was accepted, echo $transaction | jq .type
will say "execute"
If the transaction was rejected, echo $transaction | jq .type
will say "fee"
Currently no API endpoint is available to quickly check whether a transaction was aborted.
Given a confirmed transaction id, you can find the block it was included in using:
GET /<network>/find/blockHash//{transaction id}
on a fully synced snarkOS node REST endpoint- Get block hash for transaction ID on the Provable explorer
SDK - fetchData and getBlockByHash
import { AleoNetworkClient } from '@provablehq/sdk/mainnet.js';
const net = new AleoNetworkClient('https://api.explorer.provable.com/v1');
const txId = 'at14v8nt94d7xmsp3dq2glpzft6xw3x42ne753mlt8uenn8zw76dsqqc65jnf';
// Get block hash using fetchData
const res = await net.fetchData('/find/blockHash/' + txId);
// Get block by using getBlockByHash
const block = await net.getBlockByHash(res)
// Get block height by response json
console.log(block.header.metadata.height);
Parsing the Sender Address from transfer_public or transfer_public_as_signer Executions
Note that the sender address might be an externally owned account (EOA), i.e. owned by a user, or it might be the address of an Aleo program.
The sender address of a Transaction is present as the first argument of the first output. The following will return a human readable string containing the public values of the first output.
echo $transaction | jq '.execution.transitions[0].outputs[0].value'
Unfortunately, the current snarkOS and explorer REST endpoints return execution outputs as a string which is not compatible with JSON. You'll still need to extract the first value from it. The sender address can be parsed for example using a regex or by parsing out the 5th line:
echo $(echo $transaction | jq '.execution.transitions[0].outputs[0].value') | sed -n '5p'
Summarized Block Contents
A block contains confirmed transactions.
A confirmed transaction can either have status "accepted" or "rejected", and type "deploy" or "execute", and it contains a "transaction" and optional "rejected" object.
- A "transaction" can have type "fee", "execute" or "deploy".
- A "rejected" can have type "execution" or "deployment".
{
…,
"transactions": [
"status": "accepted"/"rejected"
"type": "deploy"/"execute",
"transaction": {
…,
"type": "fee"/"execute"/"deploy"
}
"rejected": {
…,
"type": "execution"/"deployment"
}
],
"unconfirmed_transaction_ids": [...]
}