Coverage Report

Created: 2026-09-14 20:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/tmp/bitcoin/src/index/txindex_key.h
Line
Count
Source
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
57
    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
    SERIALIZE_METHODS(BlockTxPosition, obj)
67
4.89k
    {
68
4.89k
        READWRITE(VARINT(obj.block_seq),
69
4.89k
                  Using<BigEndianFormatter<TX_OFFSET_SIZE>>(obj.tx_offset_in_block));
70
4.89k
    }
void txindex::BlockTxPosition::SerializationOps<SpanReader, txindex::BlockTxPosition, ActionUnserialize>(txindex::BlockTxPosition&, SpanReader&, ActionUnserialize)
Line
Count
Source
67
324
    {
68
324
        READWRITE(VARINT(obj.block_seq),
69
324
                  Using<BigEndianFormatter<TX_OFFSET_SIZE>>(obj.tx_offset_in_block));
70
324
    }
void txindex::BlockTxPosition::SerializationOps<DataStream, txindex::BlockTxPosition const, ActionSerialize>(txindex::BlockTxPosition const&, DataStream&, ActionSerialize)
Line
Count
Source
67
4.56k
    {
68
4.56k
        READWRITE(VARINT(obj.block_seq),
69
4.56k
                  Using<BigEndianFormatter<TX_OFFSET_SIZE>>(obj.tx_offset_in_block));
70
4.56k
    }
void txindex::BlockTxPosition::SerializationOps<DataStream, txindex::BlockTxPosition, ActionUnserialize>(txindex::BlockTxPosition&, DataStream&, ActionUnserialize)
Line
Count
Source
67
4
    {
68
4
        READWRITE(VARINT(obj.block_seq),
69
4
                  Using<BigEndianFormatter<TX_OFFSET_SIZE>>(obj.tx_offset_in_block));
70
4
    }
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
    SERIALIZE_METHODS(BlockSeqKey, obj)
78
4.29k
    {
79
4.29k
        uint8_t prefix{DB_BLOCK_SEQ};
80
4.29k
        READWRITE(prefix);
81
4.29k
        if (ser_action.ForRead() && prefix != DB_BLOCK_SEQ) throw std::ios_base::failure("Invalid format for txindex block seq key");
82
4.29k
        READWRITE(VARINT(obj.block_seq));
83
4.29k
    }
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
    SERIALIZE_METHODS(BlockHashKey, obj)
91
8.78k
    {
92
8.78k
        uint8_t prefix{DB_BLOCK_HASH};
93
8.78k
        READWRITE(prefix);
94
8.78k
        if (ser_action.ForRead() && prefix != DB_BLOCK_HASH) throw std::ios_base::failure("Invalid format for txindex block hash key");
95
8.78k
        READWRITE(obj.block_hash);
96
8.78k
    }
97
};
98
99
constexpr int HASH_PREFIX_SIZE{5};
100
using TxHashKeyPrefix = uint64_t;
101
102
inline TxHashKeyPrefix CreateKeyPrefix(const SipHasher13UJ& hasher, const Txid& txid)
103
4.55k
{
104
4.55k
    return hasher.Hash(txid.ToUint256()) >> (8 * (sizeof(TxHashKeyPrefix) - HASH_PREFIX_SIZE));
105
4.55k
}
106
107
struct DBKey {
108
    TxHashKeyPrefix hash_prefix{0};
109
    BlockTxPosition pos;
110
111
    SERIALIZE_METHODS(DBKey, obj)
112
4.88k
    {
113
4.88k
        uint8_t prefix{DB_TXINDEX_HASHED};
114
4.88k
        READWRITE(prefix);
115
4.88k
        if (ser_action.ForRead() && prefix != DB_TXINDEX_HASHED) throw std::ios_base::failure("Invalid format for txindex DB key");
116
4.88k
        READWRITE(Using<BigEndianFormatter<HASH_PREFIX_SIZE>>(obj.hash_prefix), obj.pos);
117
4.88k
    }
void txindex::DBKey::SerializationOps<SpanReader, txindex::DBKey, ActionUnserialize>(txindex::DBKey&, SpanReader&, ActionUnserialize)
Line
Count
Source
112
324
    {
113
324
        uint8_t prefix{DB_TXINDEX_HASHED};
114
324
        READWRITE(prefix);
115
324
        if (ser_action.ForRead() && prefix != DB_TXINDEX_HASHED) throw std::ios_base::failure("Invalid format for txindex DB key");
116
324
        READWRITE(Using<BigEndianFormatter<HASH_PREFIX_SIZE>>(obj.hash_prefix), obj.pos);
117
324
    }
void txindex::DBKey::SerializationOps<DataStream, txindex::DBKey const, ActionSerialize>(txindex::DBKey const&, DataStream&, ActionSerialize)
Line
Count
Source
112
4.56k
    {
113
4.56k
        uint8_t prefix{DB_TXINDEX_HASHED};
114
4.56k
        READWRITE(prefix);
115
4.56k
        if (ser_action.ForRead() && prefix != DB_TXINDEX_HASHED) throw std::ios_base::failure("Invalid format for txindex DB key");
116
4.56k
        READWRITE(Using<BigEndianFormatter<HASH_PREFIX_SIZE>>(obj.hash_prefix), obj.pos);
117
4.56k
    }
118
};
119
120
//! Key of a legacy (pre-hashing) txindex row: the full txid under the 't' prefix.
121
inline std::pair<uint8_t, uint256> LegacyTxKey(const Txid& txid)
122
5
{
123
5
    return {DB_TXINDEX, txid.ToUint256()};
124
5
}
125
126
} // namespace txindex
127
128
#endif // BITCOIN_INDEX_TXINDEX_KEY_H