What is the accumulator hash?

The accumulator hash is a fixed length value that is used to verify that the current transaction, and all transactions before it, have occurred in the correct order and have not been tampered with.

How is it calculated?

The accumulator hash is calculated by hashing the previous accumulator hash with the current transaction id.

At the genesis of the Radix public network, the initial accumulator hash was set to 32 bytes of zeros: 0000000000000000000000000000000000000000000000000000000000000000

The genesis transaction had a transaction id of: 030E7094728C8D065C5DB696977696BEA9094F67BCFD4C021F99EC784E24023B

To calculate the very first accumulator hash we:

  1. Concatenate the 32 byte parent accumulator hash (0000ā€¦0000) with the 32 byte genesis transaction id (030Eā€¦023B) together to create a 64 byte value: 0000000000000000000000000000000000000000000000000000000000000000030E7094728C8D065C5DB696977696BEA9094F67BCFD4C021F99EC784E24023B
  2. We do a double SHA256 hashing operation: sha256(sha256(0000...023B))
  3. The result is the new accumulator hash: 1E62415E5FD95C63AFF69142F1359CC6A981FF7169C128D266F45ADF614D09B0

To calculate the second accumulator hash, we take the result of the previous (parent) accumulator hash, append the transaction id of the second transaction, and perform the double sha256 operation again.

The code snippet below illustrates the calculation of the first 2 accumulator hashes on the mainnet Radix public network:

import hashlib

#  32 bytes of zeros
genesis_accumulator = bytearray.fromhex("0000000000000000000000000000000000000000000000000000000000000000")

# First transaction hash
first_transaction_id = bytearray.fromhex("030E7094728C8D065C5DB696977696BEA9094F67BCFD4C021F99EC784E24023B")

inner = hashlib.sha256()
inner.update(genesis_accumulator + first_transaction_id)

outer = hashlib.sha256()
outer.update(inner.digest())

# First accumulator hash
first_accumulator = outer.digest()
print("First Accumulator hash:", first_accumulator.hex())

# Second transaction hash
second_transaction_id = bytearray.fromhex("9E4DA050269BB7114AAF2AF7339719C7CD030B19EC32F12AD85B95D5A76CB714")

inner = hashlib.sha256()
inner.update(first_accumulator + second_transaction_id)

outer = hashlib.sha256()
outer.update(inner.digest())

# Second accumulator hash
second_accumulator = outer.digest()
print("Second Accumulator hash:", second_accumulator.hex())

The calculation of the accumulator hash is repeated for every transaction that occurs on the ledger. As long as transactions occur in the same order, with the same transaction ids, then every validator node will independently calculate the same accumulator hash values and can be confident that they have not received modified transaction data.

We can confirm that our accumulator calculations are correct by comparing them to the values stored in the ledger:

Screenshot 2022-01-10 at 16.52.59

Another very important factor to note is that id of a transaction is a hash of all the instructions contained within the transaction. If any of the instructions have been tampered with inside the transaction, then the transaction id will change.

In this way, the accumulator hash is a very simple, but powerful way of ensuring the integrity of transactions on the ledger.

Run this on Replit:

1 Like

Would it be possible to manipulate the accumulator hash if nobody else was transacting on the network? Since you could manipulate the transaction id?