Skip to content
🎉 Welcome to the new Aptos Docs! Click here to submit feedback!
BuildSDKsGo SDKTransactionsBatching Transactions

Batching Transactions

The Go SDK has a built-in way to send many transactions concurrently, and order them. This can be a convenient tool when trying to execute multiple transactions quickly from the same account.

This can be done with client.BuildSignAndSubmitTransactions as can be seen in the below example.

Full Go Example

batch.go
// sending_concurrent_transactions shows how to submit transactions serially or concurrently on a single account
package main
 
import (
	"github.com/aptos-labs/aptos-go-sdk"
	"github.com/aptos-labs/aptos-go-sdk/api"
	"time"
)
 
func setup(networkConfig aptos.NetworkConfig) (*aptos.Client, aptos.TransactionSigner) {
	client, err := aptos.NewClient(networkConfig)
	if err != nil {
		panic("Failed to create client:" + err.Error())
	}
 
	sender, err := aptos.NewEd25519Account()
	if err != nil {
		panic("Failed to create sender:" + err.Error())
	}
 
	err = client.Fund(sender.Address, 100_000_000)
	if err != nil {
		panic("Failed to fund sender:" + err.Error())
	}
 
	return client, sender
}
 
func payload() aptos.TransactionPayload {
	receiver := aptos.AccountAddress{}
	err := receiver.ParseStringRelaxed("0xBEEF")
	if err != nil {
		panic("Failed to parse address:" + err.Error())
	}
	amount := uint64(100)
	p, err := aptos.CoinTransferPayload(nil, receiver, amount)
	if err != nil {
		panic("Failed to serialize arguments:" + err.Error())
	}
	return aptos.TransactionPayload{Payload: p}
}
 
func sendManyTransactionsSerially(networkConfig aptos.NetworkConfig, numTransactions uint64) {
	client, sender := setup(networkConfig)
 
	responses := make([]*api.SubmitTransactionResponse, numTransactions)
	payload := payload()
 
	senderAddress := sender.AccountAddress()
	sequenceNumber := uint64(0)
	for i := uint64(0); i < numTransactions; i++ {
		rawTxn, err := client.BuildTransaction(senderAddress, payload, aptos.SequenceNumber(sequenceNumber))
		if err != nil {
			panic("Failed to build transaction:" + err.Error())
		}
 
		signedTxn, err := rawTxn.SignedTransaction(sender)
		if err != nil {
			panic("Failed to sign transaction:" + err.Error())
		}
 
		submitResult, err := client.SubmitTransaction(signedTxn)
		if err != nil {
			panic("Failed to submit transaction:" + err.Error())
		}
		responses[i] = submitResult
		sequenceNumber++
	}
 
	// Wait on last transaction
	response, err := client.WaitForTransaction(responses[numTransactions-1].Hash)
	if err != nil {
		panic("Failed to wait for transaction:" + err.Error())
	}
	if response.Success == false {
		panic("Transaction failed due to " + response.VmStatus)
	}
}
 
func sendManyTransactionsConcurrently(networkConfig aptos.NetworkConfig, numTransactions uint64) {
	client, sender := setup(networkConfig)
	payload := payload()
 
	// start submission goroutine
	payloads := make(chan aptos.TransactionBuildPayload, 50)
	results := make(chan aptos.TransactionSubmissionResponse, 50)
	go client.BuildSignAndSubmitTransactions(sender, payloads, results)
 
	// Submit transactions to goroutine
	go func() {
		for i := uint64(0); i < numTransactions; i++ {
			payloads <- aptos.TransactionBuildPayload{
				Id:    i,
				Type:  aptos.TransactionSubmissionTypeSingle,
				Inner: payload,
			}
		}
		close(payloads)
	}()
 
	// Wait for all transactions to be processed
	for result := range results {
		if result.Err != nil {
			panic("Failed to submit and wait for transaction:" + result.Err.Error())
		}
	}
}
 
// example This example shows you how to improve performance of the transaction submission
//
// Speed can be improved by locally handling the sequence number, gas price, and other factors
func example(networkConfig aptos.NetworkConfig, numTransactions uint64) {
	println("Sending", numTransactions, "transactions Serially")
	startSerial := time.Now()
	sendManyTransactionsSerially(networkConfig, numTransactions)
	endSerial := time.Now()
	println("Serial:", time.Duration.Milliseconds(endSerial.Sub(startSerial)), "ms")
 
	println("Sending", numTransactions, "transactions Concurrently")
	startConcurrent := time.Now()
	sendManyTransactionsConcurrently(networkConfig, numTransactions)
	endConcurrent := time.Now()
	println("Concurrent:", time.Duration.Milliseconds(endConcurrent.Sub(startConcurrent)), "ms")
 
	println("Concurrent is", time.Duration.Milliseconds(endSerial.Sub(startSerial)-endConcurrent.Sub(startConcurrent)), "ms faster than Serial")
}
 
func main() {
	example(aptos.DevnetConfig, 100)
}