Project TXA
Search
⌃K

Storage and Operations

The Ledger Engine should utilize a key-value based database with support for transactions like RocksDB to store UTXOs and State Updates.

UTXO Storage

  • UTXOStore: Hash(UTXO) -> Serialize(UTXO)
    • Append-only
    • Stores Raw UTXO by its hash
  • SpentStore: SpentKey:Hash(UTXO) -> Boolean
    • Append-only
    • Flags a UTXO hash as spent
  • SettledStore: SettledKey:Hash(UTXO) -> Boolean
    • Append-only
    • Flags a UTXO hash as settled
  • WalletStore: Hash(Wallet,Asset,ChainId) -> Serialize(Hash(UTXO)[])
    • Stores list of unspent UTXO hashes for a single trader and asset
  • BalanceStore: BalanceKey:Hash(Wallet,Asset,ChainId) -> Uint
    • Stores sum of unspent UTXO amounts for a single trader and asset

State Update Storage

  • SequenceIdStore: SequenceKey -> Uint
    • Stores next sequence number
  • StateUpdateStore: StateUpdateKey:Uint -> Serialize(StateUpdate)
    • Stores raw State Update by its sequence number
  • ChainSequenceIdStore: Uint -> Uint
    • Maps chain ID to latest chain sequence ID

Merkle Storage

  • LeafStore: Uint -> LeafHash
    • Append-only
    • Index of leaf in tree

Operations

Generating State Updates

  • processDeposit(Deposit deposit)
    • MUST be atomic
    • using chainId of deposit, query for latest id from ChainSequenceIdStore. Assert that the chainSequenceId of the deposit is one after the latest id. Update the latest id.
    • hash deposit to obtain UTXO hash depositHash
    • Can be done in parallel:
      • using depositHash, store the deposit in UTXOStore
      • get wallet and asset from deposit, hash to get key for WalletStore.
        • Get and deserialize existing list of hashes from WalletStore, append depositHash, serialize and update value in WalletStore
        • append BalanceKey to last key, get value from BalanceStore. Add amount from deposit, update value in BalanceStore
      • using SequenceKey, get next sequence number from SequenceStore
        • using sequence number and the deposit , create a StateUpdate
        • serialize DepositParams and store using sequence number as key in StateUpdateStore
  • processTrade(TradeParams trade)
    • using size and price of trade, calculate amount of each asset that needs to be paid
    • Determine trader and asset for side A of the trade. Hash to get key for WalletStore. Get and deserialize list of UTXO hashes from WalletStore to use as inputs for this side of the trade.
    • Determine trader and asset for side A of the trade. Hash to get key for WalletStore. Get and deserialize list of UTXO hashes from WalletStore to use as inputs for this side of the trade.
    • Determine inputs and outputs for Side A:
      • Iterate through list of UTXO hashes to use as inputs for side A
        • Using UTXO hash as key, get and deserialize raw UTXO from UTXOStore
        • add UTXO amount to totalInputAmount and add UTXO hash to list of inputs
        • Compare amount from UTXO with remaining amount to be paid
          • if amount of UTXO is less than or equal to remaining amount:
            • create 1 ObligationUTXO crediting the entire UTXO amount (minus fees) to the counterparty
              • append the resulting UTXO to list of outputs for side A. It will be processed as if it was a deposit for the counterparty.
            • create 1 FeeUTXO crediting the settlement fee to the SDP placeholder address
              • append the resulting UTXO to list of outputs for side A. It will be processed as if it was a deposit for the SDP address, except marked as spent
            • create 1 FeeUTXO crediting the PI fee to the PI fee recipient address
              • append the resulting UTXO to list of outputs for side A. It will be processed as if it was a deposit for the PI fee recipient address, except marked as spent
          • if amount of UTXO is greater than remaining amount to be paid:
            • create 1 ObligationUTXO crediting the UTXO amount minus the remaining amount (minus fees) to the counterparty
              • append the resulting UTXO to list of outputs for side A. It will be processed as if it was a deposit for the counterparty.
            • create 1 Obligation UTXO crediting the UTXO amount minus the remaining amount to the party (same trader as the input)
              • append the resulting UTXO to list of outputs for side A. It will be processed as if it was a deposit for the party.
            • create 1 FeeUTXO crediting the PI fee to the PI fee recipient address
              • process the resulting UTXO as if it was a deposit for the PI fee recipient address, except mark it as spent
            • create 1 FeeUTXO crediting the settlement fee to the SDP placeholder address
              • process the resulting UTXO as if it was a deposit for the SDP address, except mark it as spent
          • append the input to the list of inputs for side A. Update the remaining amount to be paid. Stop iterating if the remaining amount is 0.
          • after iteration ends, use trader and asset to construct key for BalanceStore and query for the amount. Subtract totalInputAmount from the value and update it.
      • repeat the above for side B of trade
      • Mark all inputs in side A and side B as spent
      • Iterate through all outputs of side A and side B and append them to the ledger
      • using SequenceKey, get next sequence number from SequenceStore
        • using sequence number and inputs and outputs determine for each side , create Trade
        • serialize Trade and store using sequence number as key in StateUpdateStore
  • processSettlementRequest(SettlementRequest settlementRequest)
    • using chainId of settlementRequest, query for latest id from ChainSequenceIdStore. Assert that the chainSequenceId of the settlement request is one after the latest id. Update the latest Id.
    • using trader and asset of settlementRequest, construct key for WalletStore and query for list of unspent UTXO hashes
    • Iterate through every UTXO hash
      • append SettledKey to the hash and set it as true in SettledStore
      • append SpentKey to the hash and set it as true in SpentStore
      • use the hash to query for the UTXO in the UTXOStore. Query for the raw UTXO and add the amount of the UTXO to a totalAmount
    • using trader and asset of settlementRequest, construct key for WalletStore and set the value to empty
    • using trader and asset of settlementRequest, construct key for BalanceStore and set the value to 0
    • using the settlementRequest and list of UTXO hashes, construct and return a SettlementAcknowledgement
    • using SequenceKey, get next sequence number from SequenceStore
      • using sequence number, SettlementRequest, and inputs, create SettlementAcknowledgement
      • serialize SettlementAcknowledgement and store using sequence number as key in StateUpdateStore

Validating State Updates

  • validateStateUpdate(SignedStateUpdate proposedStateUpdate, ChainEventStore eventStore)
    • validate that the address recovered from the signature of the proposedStateUpdate matches the address of the participatingInterface set in the state update
    • validate that the sequenceId of the proposedStateUpdate is the next id in the sequence after the stored lastProcessedStateUpdate
    • Deserialize the structData based on the typeIdentifier and call the corresponding function to validate the state update
    • if the validate function specific to the state update returns true, then commit the changes and return true
      • if invalid, forward the signed state update to the fraud engine
  • validateDeposit(DepositAcknowledgement proposedDeposit, ChainEventStore eventStore)
    • using chainId and chainSequenceId of the proposedDeposit.deposit, query for the corresponding event in the eventStore
      • if event is missing, wait and try again
    • assert that the event from the eventStore matches the deposit
    • get Deposit from proposedDeposit and use as input to processDeposit
    • validate that the output generated by processDeposit matches the output in proposedDeposit
  • validateTrade(Trade proposedTrade)
    • get TradeParams from proposedTrade and use as input in processTrade
    • validate that the inputs and outputs generated by processTrade match the inputs and outputs in the proposedTrade. Return true if so, otherwise return false
  • validateSettlement(SettlementAcknowledgement proposedSettlement, ChainEventStore eventStore)
    • using chainId and chainSequenceId of the proposedSettlement.settlementRequest, query for the corresponding event in the eventStore
      • if event is missing, wait and try again
    • assert that the event from the eventStore matches the settlement request
    • get SettlementRequest from proposedSettlement and use as input in processSettlementRequest
    • validate that the inputs generated by processSettlementRequest match the inputs in the proposedSettlement. Return true if so, otherwise return false