Go SDK - 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
Section titled “Full Go Example”// sending_concurrent_transactions shows how to submit transactions serially or concurrently on a single accountpackage 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 factorsfunc 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)}