Locating a Transaction using the Archiver/Indexer with Java
This tutorial walks through using the archival and indexer modes to locate older transactions with Java. 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. 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
2. 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 com.algorand.javatest;
import java.math.BigInteger;
import com.algorand.algosdk.algod.client.AlgodClient;
import com.algorand.algosdk.algod.client.ApiException;
import com.algorand.algosdk.algod.client.api.AlgodApi;
import com.algorand.algosdk.algod.client.auth.ApiKeyAuth;
import com.algorand.algosdk.algod.client.model.Transaction;
import com.algorand.algosdk.algod.client.model.TransactionList;
import com.algorand.algosdk.algod.client.model.TransactionParams;
import org.threeten.bp.LocalDate;
public class FindTransaction {
public static void main(String args[]) throws Exception {
final String ALGOD_API_ADDR = <"http://algod-address:port">;
final String ALGOD_API_TOKEN = <"algod-token">;
AlgodClient client = (AlgodClient) new AlgodClient().setBasePath(ALGOD_API_ADDR);
ApiKeyAuth api_key = (ApiKeyAuth) client.getAuthentication("api_key");
api_key.setApiKey(ALGOD_API_TOKEN);
AlgodApi algodApiInstance = new AlgodApi(client);
String txid = "5EBI7BNG6BZH66KLKAXCKNOPZPG3V32CU2MR52XMWXWPEQ4POF4A";
String address ="FCG5AE4EK7UDBKONUZGQRYNC2HWRASPID3T73HBHJKVM2J72I35XUU62MA";
try {
Transaction tx1 = algodApiInstance.transactionInformation(address, txid);
System.out.println("Tx1 = " + tx1.toString());
} catch (ApiException e) {
e.printStackTrace();
}
}
}
This operation will only search up to the last 1000 blocks. If the transaction is older than this, the call will return an error.
3. 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 com.algorand.javatest;
import java.math.BigInteger;
import com.algorand.algosdk.algod.client.AlgodClient;
import com.algorand.algosdk.algod.client.ApiException;
import com.algorand.algosdk.algod.client.api.AlgodApi;
import com.algorand.algosdk.algod.client.auth.ApiKeyAuth;
import com.algorand.algosdk.algod.client.model.Transaction;
import com.algorand.algosdk.algod.client.model.TransactionList;
import com.algorand.algosdk.algod.client.model.TransactionParams;
import org.threeten.bp.LocalDate;
public class FindTransaction {
public static void main(String args[]) throws Exception {
final String ALGOD_API_ADDR = <"http://algod-address:port">;
final String ALGOD_API_TOKEN = <"algod-token">;
AlgodClient client = (AlgodClient) new AlgodClient().setBasePath(ALGOD_API_ADDR);
ApiKeyAuth api_key = (ApiKeyAuth) client.getAuthentication("api_key");
api_key.setApiKey(ALGOD_API_TOKEN);
AlgodApi algodApiInstance = new AlgodApi(client);
String txid = "5EBI7BNG6BZH66KLKAXCKNOPZPG3V32CU2MR52XMWXWPEQ4POF4A";
String address ="FCG5AE4EK7UDBKONUZGQRYNC2HWRASPID3T73HBHJKVM2J72I35XUU62MA";
try {
TransactionParams params = algodApiInstance.transactionParams();
TransactionList txList = algodApiInstance.transactions(address,
params.getLastRound().subtract(BigInteger.valueOf(10000)),
params.getLastRound(),
null, null,
BigInteger.valueOf(1));
for (Transaction tx : txList.getTransactions()) {
System.out.println("Tx2 = " + tx.toString());
}
} catch (ApiException e) {
e.printStackTrace();
}
}
}
This will return the transaction if the transaction is in the 1k block range specified as parameters.
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 com.algorand.javatest;
import java.math.BigInteger;
import com.algorand.algosdk.algod.client.AlgodClient;
import com.algorand.algosdk.algod.client.ApiException;
import com.algorand.algosdk.algod.client.api.AlgodApi;
import com.algorand.algosdk.algod.client.auth.ApiKeyAuth;
import com.algorand.algosdk.algod.client.model.Transaction;
import com.algorand.algosdk.algod.client.model.TransactionList;
import com.algorand.algosdk.algod.client.model.TransactionParams;
import org.threeten.bp.LocalDate;
public class FindTransaction {
public static void main(String args[]) throws Exception {
final String ALGOD_API_ADDR = <"http://algod-address:port">;
final String ALGOD_API_TOKEN = <"algod-token">;
AlgodClient client = (AlgodClient) new AlgodClient().setBasePath(ALGOD_API_ADDR);
ApiKeyAuth api_key = (ApiKeyAuth) client.getAuthentication("api_key");
api_key.setApiKey(ALGOD_API_TOKEN);
AlgodApi algodApiInstance = new AlgodApi(client);
String txid = "5EBI7BNG6BZH66KLKAXCKNOPZPG3V32CU2MR52XMWXWPEQ4POF4A";
String address ="FCG5AE4EK7UDBKONUZGQRYNC2HWRASPID3T73HBHJKVM2J72I35XUU62MA";
try {
// locate transactions with dates
LocalDate today = LocalDate.now();
LocalDate yesterday = today.minusDays(1);
System.out.println("yesderday = " + yesterday);
TransactionList txList2 = algodApiInstance.transactions(address,
null,
null,
yesterday, today,
BigInteger.valueOf(5));
for (Transaction tx : txList2.getTransactions()) {
System.out.println("Tx3 = " + tx.toString());
}
// locate transaction with just txid
Transaction tx4 = algodApiInstance.transaction( txid );
System.out.println("Tx4 = " + tx4.toString());
} catch (ApiException e) {
e.printStackTrace();
}
}
}