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.
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:
The genesis transaction had a transaction id of:
To calculate the very first accumulator hash we:
- 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:
- We do a double SHA256 hashing operation:
- The result is the new accumulator hash:
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:
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.