Teranode Data Model - UTXO
UTXO Data Model
For every transaction, a UTXO record is stored in the database. The record contains the following fields:
Field Name | Data Type | Description |
---|---|---|
utxos | Array of Byte[32] or Byte[64] |
A list of UTXOs, where each UTXO is either 32 bytes (unspent) or 64 bytes (spent). |
utxoSpendableIn | Map<Integer, Integer> |
A map where the key is the UTXO offset and the value is the block height after which the UTXO is spendable. |
recordUtxos | Integer |
Total number of UTXOs in this record. |
spentUtxos | Integer |
Number of UTXOs that have been spent in this record. |
frozen | Boolean |
Indicates whether the UTXO or transaction is frozen. |
unspendable | Boolean |
Indicates whether the transaction outputs can be spent. Set to true during initial creation when the transaction is validated. Set to false in two scenarios: (1) immediately after successful addition to block assembly, or (2) when the transaction is mined in a block through the SetMinedMulti operation. |
conflicting | Boolean |
Indicates whether this transaction is a double spend. |
conflictingChildren | Array<chainhash.Hash> |
List of transaction hashes that spend from this transaction and are also marked as conflicting. |
spendingHeight | Integer |
If the UTXO is from a coinbase transaction, it stores the block height after which it can be spent. |
blockIDs | Array<Integer> |
List of block IDs that reference this UTXO. |
blockHeights | Array<uint32> |
List of block heights where this transaction appears. Used by the validator to identify the height at which a UTXO was mined. |
subtreeIdxs | Array<int> |
List of subtree indexes where this transaction appears within blocks. |
external | Boolean |
Flag indicating whether the transaction is stored externally (used for fetching external raw transaction data). |
totalExtraRecs | Integer (Optional) |
The number of UTXO records associated with the transaction, used for pagination. |
reassignments | Array<Map> |
Tracks UTXO reassignments. Contains maps with keys such as offset , utxoHash , newUtxoHash , and blockHeight . |
tx | bt.Tx Object |
Raw transaction data containing inputs, outputs, version, and locktime. |
fee | Integer |
Transaction fee associated with this UTXO. |
sizeInBytes | Integer |
The size of the transaction in bytes. |
parentTxHashes | Array<chainhash.Hash> |
List of parent transaction hashes (from the transaction inputs). |
isCoinbase | Boolean |
Indicates whether this UTXO is from a coinbase transaction. |
Within it, each UTXO in the utxos
array has the following fields:
Field Name | Data Type | Description |
---|---|---|
utxoHash | Byte[32] |
32-byte little-endian hash representing the UTXO. |
spendingTxID | Byte[32] |
32-byte little-endian hash representing the transaction ID that spent this UTXO (only present for spent UTXOs). |
existingUTXOHash | Byte[32] |
Extracted from a UTXO to validate that the UTXO matches the provided utxoHash . |
existingSpendingTxID | Byte[32] |
If the UTXO has been spent, this field stores the spending transaction ID. |
Additionally, note how the raw transaction data (tx (bt.Tx Object)) is stored in the record. This includes:
- Version: The transaction version.
- LockTime: The transaction lock time.
- Inputs: Array of inputs used in the transaction.
- Outputs: Array of outputs (UTXOs) created by the transaction.
Time to Live (TTL) Fields
Typically, UTXO records are kept with a time-to-live value that is set when all UTXOs in a record are spent or reassigned.
Field Name | Data Type | Description |
---|---|---|
TTL | Integer |
Time-to-live value for the record. Set when: - All UTXOs in a record are spent or reassigned - Transaction is marked as conflicting |
Aerospike Storage
If storing in Aerospike, the UTXO record is stored as a bin in the Aerospike database. The bin contains the UTXO data in a serialized format, containing up to 1024 bytes.
For more information, please refer to the official Aerospike documentation: https://aerospike.com.
UTXO MetaData
For convenience, the UTXO can be decorated using the UTXO MetaData
format, widely used in Teranode:
Field Name | Description | Data Type |
---|---|---|
Tx | The raw transaction data. | *bt.Tx Object |
Hash | Unique identifier for the transaction. | String/Hexadecimal |
Fee | The fee associated with the transaction. | Decimal |
Size in Bytes | The size of the transaction in bytes. | Integer |
ParentTxHashes | List of hashes representing the parent transactions. | Array of Strings/Hexadecimals |
BlockIDs | List of IDs of the blocks that include this transaction. | Array of Integers |
BlockHeights | List of block heights where this transaction appears. | Array of Integers |
SubtreeIdxs | List of subtree indexes where this transaction appears within blocks. | Array of Integers |
LockTime | The earliest time or block number that this transaction can be included in the blockchain. | Integer/Timestamp or Block Number |
IsCoinbase | Indicates whether the transaction is a coinbase transaction. | Boolean |
Unspendable | Flag indicating whether the transaction outputs can be spent. Part of the two-phase commit process for block assembly. | Boolean |
Conflicting | Indicates whether this transaction is a double spend. | Boolean |
ConflictingChildren | List of transaction hashes that spend from this transaction and are also marked as conflicting. | Array of Strings/Hexadecimals |
Note:
-
Parent Transactions: 1 or more parent transaction hashes. For each input that our transaction has, we can have a different parent transaction. I.e. a TX can be spending UTXOs from multiple transactions.
-
Blocks: 1 or more block hashes. Each block represents a block that mined the transaction.
-
Typically, a tx should only belong to one block. i.e. a) a tx is created (and its meta is stored in the UTXO store) and b) the tx is mined, and the mined block hash is tracked in the UTXO store for the given transaction.
-
However, in the case of a fork, a tx can be mined in multiple blocks by different nodes. In this case, the UTXO store will track multiple block hashes for the given transaction, until such time that the fork is resolved and only one block is considered valid.
-
Block Heights and Subtree Indexes: These fields track the exact location of transactions within the blockchain.
- The block heights array is particularly important for validation, as it gives visibility on what height a UTXO was mined. While most UTXOs are mined at the same height across parallel chains or forks, this is not always the case. Storing this information enables the validator to efficiently determine the height of UTXOs being spent without performing expensive lookups. Block heights indicate how deep in the chain a transaction is, which is important for maturity checks.
- The subtree indexes are primarily informational, allowing for future features that might need to locate exactly where a transaction was placed within a block's structure, enabling potential parallel processing and efficient lookups.