Skip to content
  • Dave Collins's avatar
    multi: Rework utxoset/view to use outpoints. · a59ac5b1
    Dave Collins authored
    This modifies the utxoset in the database and related UtxoViewpoint to
    store and work with unspent transaction outputs on a per-output basis
    instead of at a transaction level.  This was inspired by similar recent
    changes in Bitcoin Core.
    
    The primary motivation is to simplify the code, pave the way for a
    utxo cache, and generally focus on optimizing runtime performance.
    
    The tradeoff is that this approach does somewhat increase the size of
    the serialized utxoset since it means that the transaction hash is
    duplicated for each output as a part of the key and some additional
    details such as whether the containing transaction is a coinbase and the
    block height it was a part of are duplicated in each output.
    
    However, in practice, the size difference isn't all that large, disk
    space is relatively cheap, certainly cheaper than memory, and it is much
    more important to provide more efficient runtime operation since that is
    the ultimate purpose of the daemon.
    
    While performing this conversion, it also simplifies the code to remove
    the transaction version information from the utxoset as well as the
    spend journal.  The logic for only serializing it under certain
    circumstances is complicated and it isn't actually used anywhere aside
    from the gettxout RPC where it also isn't used by anything important
    either.  Consequently, this also removes the version field of the
    gettxout RPC result.
    
    The utxos in the database are automatically migrated to the new format
    with this commit and it is possible to interrupt and resume the
    migration process.
    
    Finally, it also updates the tests for the new format and adds a new
    function to the tests to convert the old test data to the new format for
    convenience.  The data has already been converted and updated in the
    commit.
    
    An overview of the changes are as follows:
    
    - Remove transaction version from both spent and unspent output entries
      - Update utxo serialization format to exclude the version
      - Modify the spend journal serialization format
        - The old version field is now reserved and always stores zero and
          ignores it when reading
        - This allows old entries to be used by new code without having to
          migrate the entire spend journal
      - Remove version field from gettxout RPC result
    - Convert UtxoEntry to represent a specific utxo instead of a
      transaction with all remaining utxos
      - Optimize for memory usage with an eye towards a utxo cache
        - Combine details such as whether the txout was contained in a
          coinbase, is spent, and is modified into a single packed field of
          bit flags
        - Align entry fields to eliminate extra padding since ultimately
          there will be a lot of these in memory
        - Introduce a free list for serializing an outpoint to the database
          key format to significantly reduce pressure on the GC
      - Update all related functions that previously dealt with transaction
        hashes to accept outpoints instead
      - Update all callers accordingly
      - Only add individually requested outputs from the mempool when
        constructing a mempool view
    - Modify the spend journal to always store the block height and coinbase
      information with every spent txout
      - Introduce code to handle fetching the missing information from
        another utxo from the same transaction in the event an old style
        entry is encountered
        - Make use of a database cursor with seek to do this much more
          efficiently than testing every possible output
    - Always decompress data loaded from the database now that a utxo entry
      only consists of a specific output
    - Introduce upgrade code to migrate the utxo set to the new format
      - Store versions of the utxoset and spend journal buckets
      - Allow migration process to be interrupted and resumed
    - Update all tests to expect the correct encodings, remove tests that no
      longer apply, and add new ones for the new expected behavior
      - Convert old tests for the legacy utxo format deserialization code to
        test the new function that is used during upgrade
      - Update the utxostore test data and add function that was used to
        convert it
    - Introduce a few new functions on UtxoViewpoint
      - AddTxOut for adding an individual txout versus all of them
      - addTxOut to handle the common code between the new AddTxOut and
        existing AddTxOuts
      - RemoveEntry for removing an individual txout
      - fetchEntryByHash for fetching any remaining utxo for a given
        transaction hash
    a59ac5b1