Branch data Line data Source code
1 : : // Copyright (c) The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #ifndef BITCOIN_INDEX_TXINDEX_KEY_H
6 : : #define BITCOIN_INDEX_TXINDEX_KEY_H
7 : :
8 : : #include <consensus/consensus.h>
9 : : #include <crypto/siphash.h>
10 : : #include <primitives/transaction_identifier.h>
11 : : #include <serialize.h>
12 : : #include <uint256.h>
13 : :
14 : : #include <array>
15 : : #include <cstddef>
16 : : #include <cstdint>
17 : : #include <ios>
18 : : #include <string>
19 : : #include <utility>
20 : :
21 : : namespace txindex {
22 : : /*
23 : : * Database layout:
24 : : *
25 : : * ['x', hash prefix, block seq, tx offset] -> (empty)
26 : : * ['s', block seq] -> block hash
27 : : * ['h', block hash] -> block seq
28 : : * ["next_block_seq"] -> next block seq to assign
29 : : * ["txid_hash_salt"] -> txid hasher salt
30 : : * ["best_block_v2"] -> current sync locator
31 : : * ['t', txid] -> legacy CDiskTxPos
32 : : * ['B'] -> legacy sync locator
33 : : */
34 : :
35 : : constexpr uint8_t DB_TXINDEX_HASHED{'x'};
36 : : constexpr uint8_t DB_BLOCK_SEQ{'s'};
37 : : constexpr uint8_t DB_BLOCK_HASH{'h'};
38 : : inline const std::string DB_NEXT_BLOCK_SEQ{"next_block_seq"};
39 : : inline const std::string DB_TXID_HASH_SALT{"txid_hash_salt"};
40 : : inline const std::string DB_BEST_BLOCK_V2{"best_block_v2"};
41 : : //! Prefix of a legacy (pre-hashing) txindex row.
42 : : constexpr uint8_t DB_TXINDEX{'t'};
43 : :
44 : : //! Empty value of a hashed txindex row, whose position is encoded in its key.
45 : : inline constexpr std::array<std::byte, 0> EMPTY_VALUE{};
46 : :
47 : : //! Serialized size of a block header, the offset of the first byte after it.
48 : : constexpr uint32_t BLOCK_HEADER_SIZE{80};
49 : :
50 : : //! The location of a transaction: the sequence number of the block that contains it
51 : : //! and the transaction's serialized byte offset from the start of that block
52 : : //! (including the header), so the on-disk position is simply
53 : : //! block_data_pos + tx_offset_in_block.
54 : : //!
55 : : struct BlockTxPosition {
56 : : uint32_t block_seq{0};
57 : : uint32_t tx_offset_in_block{0};
58 : :
59 : : friend bool operator==(const BlockTxPosition&, const BlockTxPosition&) = default;
60 : :
61 : : // tx_offset is encoded in 3-byte big-endian integer.
62 : : // This can hold up to 16,777,216, which is >4x the maximum 4 million block weight position
63 : : static constexpr uint32_t TX_OFFSET_SIZE{3};
64 : : static_assert(MAX_BLOCK_SERIALIZED_SIZE <= BigEndianFormatter<TX_OFFSET_SIZE>::MAX);
65 : :
66 : 0 : SERIALIZE_METHODS(BlockTxPosition, obj)
67 : : {
68 : 0 : READWRITE(VARINT(obj.block_seq),
69 : : Using<BigEndianFormatter<TX_OFFSET_SIZE>>(obj.tx_offset_in_block));
70 : 0 : }
71 : : };
72 : :
73 : : //! Key for looking up the hash of the block with the given sequence number.
74 : : struct BlockSeqKey {
75 : : uint32_t block_seq{0};
76 : :
77 : 0 : SERIALIZE_METHODS(BlockSeqKey, obj)
78 : : {
79 : 0 : uint8_t prefix{DB_BLOCK_SEQ};
80 : 0 : READWRITE(prefix);
81 : : if (ser_action.ForRead() && prefix != DB_BLOCK_SEQ) throw std::ios_base::failure("Invalid format for txindex block seq key");
82 : 0 : READWRITE(VARINT(obj.block_seq));
83 : 0 : }
84 : : };
85 : :
86 : : //! Key for looking up the sequence number assigned to the block with the given hash.
87 : : struct BlockHashKey {
88 : : uint256 block_hash;
89 : :
90 : 0 : SERIALIZE_METHODS(BlockHashKey, obj)
91 : : {
92 : 0 : uint8_t prefix{DB_BLOCK_HASH};
93 : 0 : READWRITE(prefix);
94 : : if (ser_action.ForRead() && prefix != DB_BLOCK_HASH) throw std::ios_base::failure("Invalid format for txindex block hash key");
95 : 0 : READWRITE(obj.block_hash);
96 : 0 : }
97 : : };
98 : :
99 : : constexpr int HASH_PREFIX_SIZE{5};
100 : : using TxHashKeyPrefix = uint64_t;
101 : :
102 : 0 : inline TxHashKeyPrefix CreateKeyPrefix(const SipHasher13UJ& hasher, const Txid& txid)
103 : : {
104 : 0 : return hasher.Hash(txid.ToUint256()) >> (8 * (sizeof(TxHashKeyPrefix) - HASH_PREFIX_SIZE));
105 : : }
106 : :
107 : : struct DBKey {
108 : : TxHashKeyPrefix hash_prefix{0};
109 : : BlockTxPosition pos;
110 : :
111 : 0 : SERIALIZE_METHODS(DBKey, obj)
112 : : {
113 : 0 : uint8_t prefix{DB_TXINDEX_HASHED};
114 : 0 : READWRITE(prefix);
115 [ # # # # ]: 0 : if (ser_action.ForRead() && prefix != DB_TXINDEX_HASHED) throw std::ios_base::failure("Invalid format for txindex DB key");
116 : 0 : READWRITE(Using<BigEndianFormatter<HASH_PREFIX_SIZE>>(obj.hash_prefix), obj.pos);
117 : 0 : }
118 : : };
119 : :
120 : : //! Key of a legacy (pre-hashing) txindex row: the full txid under the 't' prefix.
121 : 0 : inline std::pair<uint8_t, uint256> LegacyTxKey(const Txid& txid)
122 : : {
123 : 0 : return {DB_TXINDEX, txid.ToUint256()};
124 : : }
125 : :
126 : : } // namespace txindex
127 : :
128 : : #endif // BITCOIN_INDEX_TXINDEX_KEY_H
|