Create Publication

We are looking for publications that demonstrate building dApps or smart contracts!
See the full list of Gitcoin bounties that are eligible for rewards.

Tutorial Thumbnail
Beginner · 15 minutes or less

Locating a Transaction using the Archiver/Indexer with Go

This tutorial walks through using the archival and indexer modes to locate older transactions with Go. With many blockchains finding older transactions can be a painful experience. Algorand provides several modes and APIs that can ease this process and improve searching performance. This tutorial covers four different search techniques.

Requirements

Background

By default, Algorand installed nodes only store the last 1000 blocks. This means using the APIs to locate a transaction committed over 1k blocks ago will fail. If an application will need historical data older than this, the node the API is connecting to can be configured to store all blocks in the ledger. This can be configured by setting the Archival property to true in the node configuration. The node configuration details are described in Node Configuration Settings. The Archival node configuration is described in Algorand Node Types.

The node can also be configured to implement a local indexer, which speeds up block searches and offers two additional API calls. The indexer can be turned on by setting the IsIndexerActive property to true. The node configuration details are described in Node Configuration Settings. The isIndexerActive node configuration is described in Algorand Node Types.

Enabling the archival mode will require the node to re-sync the entire ledger.

Steps

1. Recover Older Transaction With Achiever

With the archiver enabled you can specify 1k round ranges to search. This can be done using code similar to the following.

package main

import (

    "encoding/json"
    "fmt"

    "github.com/algorand/go-algorand-sdk/client/algod"
)

const algodAddress = <algod-address>
const algodToken = <algod-token>

const txID = "DZGAM5CCUZS4LKBYDVFDSAW2TAE73TW4KYB7EPDCM6KCO25THHPQ"
const address = "FCG5AE4EK7UDBKONUZGQRYNC2HWRASPID3T73HBHJKVM2J72I35XUU62MA"

func main() {

    algodClient, err := algod.MakeClient(algodAddress, algodToken)
    if err != nil {
        return
    }   
    // Get the suggested transaction parameters
    txParams, err := algodClient.SuggestedParams()
    if err != nil {
        fmt.Printf("error getting suggested tx params: %s\n", err)
        return
    }
    txList, err := algodClient.TransactionsByAddr(address, txParams.LastRound-1000, txParams.LastRound )
    if err != nil {
        fmt.Printf("Error retrieving transaction %s\n", txID)
        return
    }
    for _, tx2 := range txList.Transactions {
        txnJSON, err := json.MarshalIndent(tx2, "", "\t")
        if err != nil {
            fmt.Printf("Can not marshall txn data: %s\n", err)
        }
        fmt.Printf("Transaction information for tx2: %s\n", txnJSON)

    }
}

This will return the transaction if the transaction is in the 1k block range specified as parameters.

2. Create an Account and Add Funds

$goal account new -d <your-data-directory> -w <your-wallet>

Save this address for later usage in the tutorial.

Use the dispenser to add funds to the account. As part of doing this operation, a transaction id will be produced on the dispenser page which will be displayed to the right of Status: Code 200 success:. Copy this transaction id for later usage in this tutorial


Learn More
- Add Funds using Dispenser

3. Recover Recent Transaction Without Achiever/Indexer

Without the achiever or indexer turned on you have a limited search range (1k blocks). You can locate the transaction using the following code. Notice we are setting the address and txid variable to the values obtained in step 1.

package main

import (

    "encoding/json"
    "fmt"

    "github.com/algorand/go-algorand-sdk/client/algod"
)

const algodAddress = <algod-address>
const algodToken = <algod-token>

const txID = "DZGAM5CCUZS4LKBYDVFDSAW2TAE73TW4KYB7EPDCM6KCO25THHPQ"
const address = "FCG5AE4EK7UDBKONUZGQRYNC2HWRASPID3T73HBHJKVM2J72I35XUU62MA"

func main() {

    algodClient, err := algod.MakeClient(algodAddress, algodToken)
    if err != nil {
        return
    }
    tx1, err := algodClient.TransactionInformation(address, txID)
    if err != nil {
        fmt.Printf("Error retrieving transaction %s\n", txID)
        return
    }
    txnJSON, err := json.MarshalIndent(tx1, "", "\t")
    if err != nil {
        fmt.Printf("Can not marshall txn data: %s\n", err)
    }
    fmt.Printf("Transaction information for tx1: %s\n", txnJSON)    
}

This operation will only search up to the last 1000 blocks. If the transaction is older than this, the call will return an error.

4. Recover Older Transaction With Indexer

With the indexer turned on, two additional calls are made available to search the entire chain without having to specify a round range. Note that turning on the indexer also requires that the archiver also be turned on. The code below finds the transaction using two different methods. One method uses just the transaction id and the other uses the account and a date range.

package main

import (

    "encoding/json"
    "fmt"

    "github.com/algorand/go-algorand-sdk/client/algod"
)
const algodAddress = <algod-address>
const algodToken = <algod-token>

const txID = "DZGAM5CCUZS4LKBYDVFDSAW2TAE73TW4KYB7EPDCM6KCO25THHPQ"
const address = "FCG5AE4EK7UDBKONUZGQRYNC2HWRASPID3T73HBHJKVM2J72I35XUU62MA"

func main() {

    algodClient, err := algod.MakeClient(algodAddress, algodToken)
    if err != nil {
        return
    }
    // get transations in date range
    txList, err := algodClient.TransactionsByAddrForDate(address, "2020-03-08T15:00:00Z","2020-03-09T19:00:00Z" );
    if err != nil {
        fmt.Printf("Error retrieving transaction %s\n", err)
        return
    }
    for _, tx3 := range txList.Transactions {
        txnJSON, err := json.MarshalIndent(tx3, "", "\t")
        if err != nil {
            fmt.Printf("Can not marshall txn data: %s\n", err)
        }
        fmt.Printf("Transaction information for tx3: %s\n", txnJSON)

    }

    // get transaction with just the txid
    tx4, err := algodClient.TransactionByID(txID)
    if err != nil {
        fmt.Printf("Error retrieving transaction %s\n", txID)
        return
    }
    txnJSON, err := json.MarshalIndent(tx4, "", "\t")
    if err != nil {
        fmt.Printf("Can not marshall txn data: %s\n", err)
    }
    fmt.Printf("Transaction information for tx4: %s\n", txnJSON)

}