Calculating Transaction ID

Given that the transaction ID is not contained in the blockchain it has to be calculated after reading them out of the block. What am I doing wrong here:

    BlockResponse resp = blockResp.body();
    if (resp.block.containsKey("txns")) {
        var list = (List<Map<String, Object>>)resp.block.get("txns");
        for (var entry : list) {
            String s = jsonMapper.writeValueAsString(entry);
            SignedTransaction trans = jsonMapper.readValue(s, SignedTransaction.class);
            String id = trans.tx.txID();

It seems that the id doesn’t match with the ones in the app.

Any ideas what I’m doing wrong?

Also are tx IDs unique or just unique for a specific block?

The process is more complex as the transactions in blocks are compressed to remove some fields such as the genesis ID and genesis Hash (and only keep a flag indicating if those fields were present).

See for example indexer/importer.go at 26d521746522237b1554c06dc370b6fe0bbe2f24 · algorand/indexer · GitHub

The simplest solution is to fetch the block from the indexer, as opposed to algod: indexer - Algorand Developer Portal
The indexer returns blocks with all the information you may be interested in (transaction IDs, close amounts, …)

I may be mistaken, but doesn’t the indexer require an archival node? I’d like to avoid that.

I’m not seeing the flag in the json, so I can assume that algod doesn’t provide me with that information?

The indexer requires a full node.
I see the flag as hgi:

$ curl -s "" | jq
  "block": {
    "earn": 27162,
    "frac": 9733995065,
    "gen": "testnet-v1.0",
    "gh": "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
    "proto": "",
    "rate": 19999960,
    "rnd": 13819291,
    "rwcalr": 14000000,
    "rwd": "7777777777777777777777777777777777777777777777777774MSJUVU",
    "seed": "FuzMUjU9svsxVMkzeb+xjKowKaabEuVYmcWl6f+ypk4=",
    "tc": 15649796,
    "ts": 1619616946,
    "txn": "z3MximXiJdPy2yVbTDt965vCUT2Zgfqr/clB1ZRy/Do=",
    "txns": [
        "hgi": true,
        "sig": "zyh2aINzuHkR88G1bIrKZldti2X+/5i4ZYWQuAn5XiDWhlZYk1Gna+SDII+LVA4/wd2TisrwwU1q9sWDOk7qDw==",
        "txn": {
          "fee": 1000,
          "fv": 13819289,
          "lv": 13820289,
          "type": "axfer",
          "xaid": 408947

Ah, they didn’t map that flag for the java objects, makes sense. Turns out the transaction I was looking at didn’t have that flag, so no genesis hash or id required.

Guess I have to take a look at how the index does it. I’m almost certain all fields are correctly set the moment it calculates the txid. Maybe I’m missing something.

So I did some testing, message sent from the provided SDK, have the exact same transaction ID once I read them back from the block (including gensisID and hash).

But when I want to check the ID of a transaction sent by the official wallet app (no HGI entry) the txId doesn’t match up.

Does the indexer get it right?
Can you link to a transaction on TestNet?


I don’t have a node with an indexer.

hgi is indeed just for the genesis name.
On MainNet and TestNet, genesis hash is always mandatory and always must be added.

Does this work when you add it?

1 Like

That’s it!

Didn’t know the hash was required (although it makes sense)