Skip to content

Commit 9674ee9

Browse files
committed
kernel: add btck_Chain API alongside btck_BlockTreeEntry
Introduce a chain-oriented view of the block index that consumers can use instead of btck_BlockTreeEntry. A btck_Chain represents the linear sequence of blocks from tip back to genesis; because a block uniquely determines its path to genesis, a chain is fully determined by its tip and shares the same underlying CBlockIndex as the corresponding block tree entry. New chain functions: - btck_chainstate_manager_get_best_chain / _find return chains - btck_chain_get_block_header / _get_block_hash / _get_ancestor - btck_chain_get_parent (O(1) step towards genesis) - btck_chain_starts_with / _mismatch / _equals A new equivalence test to test the chain-based and entry-based queries return identical results (height, hash, header, lookup-by-hash, membership, block and spent-output reads, and previous-block stepping).
1 parent 6ca607f commit 9674ee9

4 files changed

Lines changed: 527 additions & 35 deletions

File tree

src/kernel/bitcoinkernel.cpp

Lines changed: 118 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ struct btck_BlockTreeEntry: Handle<btck_BlockTreeEntry, CBlockIndex> {};
150150
struct btck_Block : Handle<btck_Block, std::shared_ptr<const CBlock>> {};
151151
struct btck_BlockValidationState : Handle<btck_BlockValidationState, BlockValidationState> {};
152152
struct btck_TxValidationState : Handle<btck_TxValidationState, TxValidationState> {};
153+
// A chain is fully determined by its tip block, so it is represented by the
154+
// CBlockIndex of that tip - the same underlying type as a btck_BlockTreeEntry.
155+
struct btck_Chain : Handle<btck_Chain, CBlockIndex> {};
153156

154157
namespace {
155158

@@ -494,7 +497,6 @@ struct btck_Context : Handle<btck_Context, std::shared_ptr<const Context>> {};
494497
struct btck_ChainParameters : Handle<btck_ChainParameters, CChainParams> {};
495498
struct btck_ChainstateManagerOptions : Handle<btck_ChainstateManagerOptions, ChainstateManagerOptions> {};
496499
struct btck_ChainstateManager : Handle<btck_ChainstateManager, ChainMan> {};
497-
struct btck_Chain : Handle<btck_Chain, CChain> {};
498500
struct btck_BlockSpentOutputs : Handle<btck_BlockSpentOutputs, std::shared_ptr<CBlockUndo>> {};
499501
struct btck_TransactionSpentOutputs : Handle<btck_TransactionSpentOutputs, CTxUndo> {};
500502
struct btck_Coin : Handle<btck_Coin, Coin> {};
@@ -912,6 +914,32 @@ const btck_BlockTreeEntry* btck_block_tree_entry_get_ancestor(const btck_BlockTr
912914
return btck_BlockTreeEntry::ref(ancestor);
913915
}
914916

917+
btck_BlockHeader* btck_block_tree_entry_get_block_header(const btck_BlockTreeEntry* entry)
918+
{
919+
return btck_BlockHeader::create(btck_BlockTreeEntry::get(entry).GetBlockHeader());
920+
}
921+
922+
int32_t btck_block_tree_entry_get_height(const btck_BlockTreeEntry* entry)
923+
{
924+
return btck_BlockTreeEntry::get(entry).nHeight;
925+
}
926+
927+
const btck_BlockHash* btck_block_tree_entry_get_block_hash(const btck_BlockTreeEntry* entry)
928+
{
929+
return btck_BlockHash::ref(btck_BlockTreeEntry::get(entry).phashBlock);
930+
}
931+
932+
int btck_block_tree_entry_equals(const btck_BlockTreeEntry* entry1, const btck_BlockTreeEntry* entry2)
933+
{
934+
return &btck_BlockTreeEntry::get(entry1) == &btck_BlockTreeEntry::get(entry2);
935+
}
936+
937+
const btck_Chain* btck_block_tree_entry_get_chain(const btck_BlockTreeEntry* entry)
938+
{
939+
// A chain and a block tree entry share the same underlying CBlockIndex.
940+
return btck_Chain::ref(&btck_BlockTreeEntry::get(entry));
941+
}
942+
915943
btck_BlockValidationState* btck_block_validation_state_create()
916944
{
917945
return btck_BlockValidationState::create();
@@ -1062,6 +1090,17 @@ btck_ChainstateManager* btck_chainstate_manager_create(
10621090
return btck_ChainstateManager::create(std::move(chainman), opts.m_context);
10631091
}
10641092

1093+
const btck_Chain* btck_chainstate_manager_find(const btck_ChainstateManager* chainman, const btck_BlockHash* block_hash)
1094+
{
1095+
auto block_index = WITH_LOCK(btck_ChainstateManager::get(chainman).m_chainman->GetMutex(),
1096+
return btck_ChainstateManager::get(chainman).m_chainman->m_blockman.LookupBlockIndex(btck_BlockHash::get(block_hash)));
1097+
if (!block_index) {
1098+
LogDebug(BCLog::KERNEL, "A block with the given hash is not indexed.");
1099+
return nullptr;
1100+
}
1101+
return btck_Chain::ref(block_index);
1102+
}
1103+
10651104
const btck_BlockTreeEntry* btck_chainstate_manager_get_block_tree_entry_by_hash(const btck_ChainstateManager* chainman, const btck_BlockHash* block_hash)
10661105
{
10671106
auto block_index = WITH_LOCK(btck_ChainstateManager::get(chainman).m_chainman->GetMutex(),
@@ -1073,6 +1112,12 @@ const btck_BlockTreeEntry* btck_chainstate_manager_get_block_tree_entry_by_hash(
10731112
return btck_BlockTreeEntry::ref(block_index);
10741113
}
10751114

1115+
const btck_Chain* btck_chainstate_manager_get_best_chain(const btck_ChainstateManager* chainstate_manager)
1116+
{
1117+
auto& chainman = *btck_ChainstateManager::get(chainstate_manager).m_chainman;
1118+
return btck_Chain::ref(WITH_LOCK(chainman.GetMutex(), return chainman.m_best_header));
1119+
}
1120+
10761121
const btck_BlockTreeEntry* btck_chainstate_manager_get_best_entry(const btck_ChainstateManager* chainstate_manager)
10771122
{
10781123
auto& chainman = *btck_ChainstateManager::get(chainstate_manager).m_chainman;
@@ -1196,26 +1241,6 @@ btck_Block* btck_block_read(const btck_ChainstateManager* chainman, const btck_B
11961241
return btck_Block::create(block);
11971242
}
11981243

1199-
btck_BlockHeader* btck_block_tree_entry_get_block_header(const btck_BlockTreeEntry* entry)
1200-
{
1201-
return btck_BlockHeader::create(btck_BlockTreeEntry::get(entry).GetBlockHeader());
1202-
}
1203-
1204-
int32_t btck_block_tree_entry_get_height(const btck_BlockTreeEntry* entry)
1205-
{
1206-
return btck_BlockTreeEntry::get(entry).nHeight;
1207-
}
1208-
1209-
const btck_BlockHash* btck_block_tree_entry_get_block_hash(const btck_BlockTreeEntry* entry)
1210-
{
1211-
return btck_BlockHash::ref(btck_BlockTreeEntry::get(entry).phashBlock);
1212-
}
1213-
1214-
int btck_block_tree_entry_equals(const btck_BlockTreeEntry* entry1, const btck_BlockTreeEntry* entry2)
1215-
{
1216-
return &btck_BlockTreeEntry::get(entry1) == &btck_BlockTreeEntry::get(entry2);
1217-
}
1218-
12191244
btck_BlockHash* btck_block_hash_create(const unsigned char block_hash[32])
12201245
{
12211246
return btck_BlockHash::create(std::span<const unsigned char>{block_hash, 32});
@@ -1355,25 +1380,93 @@ btck_BlockValidationState* btck_chainstate_manager_process_block_header(
13551380

13561381
const btck_Chain* btck_chainstate_manager_get_active_chain(const btck_ChainstateManager* chainman)
13571382
{
1358-
return btck_Chain::ref(&WITH_LOCK(btck_ChainstateManager::get(chainman).m_chainman->GetMutex(), return btck_ChainstateManager::get(chainman).m_chainman->ActiveChain()));
1383+
return btck_Chain::ref(WITH_LOCK(btck_ChainstateManager::get(chainman).m_chainman->GetMutex(), return btck_ChainstateManager::get(chainman).m_chainman->ActiveChain().Tip()));
13591384
}
13601385

13611386
int32_t btck_chain_get_height(const btck_Chain* chain)
13621387
{
13631388
LOCK(::cs_main);
1364-
return btck_Chain::get(chain).Height();
1389+
return btck_Chain::get(chain).nHeight;
1390+
}
1391+
1392+
const btck_BlockTreeEntry* btck_chain_get_tip(const btck_Chain* chain)
1393+
{
1394+
// A chain and a block tree entry share the same underlying CBlockIndex.
1395+
return btck_BlockTreeEntry::ref(&btck_Chain::get(chain));
13651396
}
13661397

13671398
const btck_BlockTreeEntry* btck_chain_get_by_height(const btck_Chain* chain, int32_t height)
13681399
{
13691400
LOCK(::cs_main);
1370-
return btck_BlockTreeEntry::ref(btck_Chain::get(chain)[height]);
1401+
return btck_BlockTreeEntry::ref(btck_Chain::get(chain).GetAncestor(height));
13711402
}
13721403

13731404
int btck_chain_contains(const btck_Chain* chain, const btck_BlockTreeEntry* entry)
13741405
{
13751406
LOCK(::cs_main);
1376-
return btck_Chain::get(chain).Contains(btck_BlockTreeEntry::get(entry)) ? 1 : 0;
1407+
const auto& tip{btck_Chain::get(chain)};
1408+
const auto& block{btck_BlockTreeEntry::get(entry)};
1409+
return tip.GetAncestor(block.nHeight) == &block ? 1 : 0;
1410+
}
1411+
1412+
btck_BlockHeader* btck_chain_get_block_header(const btck_Chain* chain, int32_t height)
1413+
{
1414+
const auto* index{btck_Chain::get(chain).GetAncestor(height)};
1415+
if (!index) {
1416+
LogDebug(BCLog::KERNEL, "The requested height is not in the chain.");
1417+
return nullptr;
1418+
}
1419+
return btck_BlockHeader::create(index->GetBlockHeader());
1420+
}
1421+
1422+
const btck_BlockHash* btck_chain_get_block_hash(const btck_Chain* chain, int32_t height)
1423+
{
1424+
const auto* index{btck_Chain::get(chain).GetAncestor(height)};
1425+
if (!index) {
1426+
LogDebug(BCLog::KERNEL, "The requested height is not in the chain.");
1427+
return nullptr;
1428+
}
1429+
return btck_BlockHash::ref(index->phashBlock);
1430+
}
1431+
1432+
const btck_Chain* btck_chain_get_ancestor(const btck_Chain* chain, int32_t height)
1433+
{
1434+
const auto* ancestor{btck_Chain::get(chain).GetAncestor(height)};
1435+
if (!ancestor) {
1436+
LogDebug(BCLog::KERNEL, "The requested height is not in the chain.");
1437+
return nullptr;
1438+
}
1439+
return btck_Chain::ref(ancestor);
1440+
}
1441+
1442+
const btck_Chain* btck_chain_get_parent(const btck_Chain* chain)
1443+
{
1444+
const auto* pprev{btck_Chain::get(chain).pprev};
1445+
if (!pprev) {
1446+
return nullptr;
1447+
}
1448+
return btck_Chain::ref(pprev);
1449+
}
1450+
1451+
int btck_chain_starts_with(const btck_Chain* chain, const btck_Chain* prefix)
1452+
{
1453+
const auto& tip{btck_Chain::get(chain)};
1454+
const auto& prefix_tip{btck_Chain::get(prefix)};
1455+
return tip.GetAncestor(prefix_tip.nHeight) == &prefix_tip ? 1 : 0;
1456+
}
1457+
1458+
const btck_Chain* btck_chain_mismatch(const btck_Chain* chain1, const btck_Chain* chain2)
1459+
{
1460+
const auto* common{LastCommonAncestor(&btck_Chain::get(chain1), &btck_Chain::get(chain2))};
1461+
if (!common) {
1462+
return nullptr;
1463+
}
1464+
return btck_Chain::ref(common);
1465+
}
1466+
1467+
int btck_chain_equals(const btck_Chain* chain1, const btck_Chain* chain2)
1468+
{
1469+
return &btck_Chain::get(chain1) == &btck_Chain::get(chain2) ? 1 : 0;
13771470
}
13781471

13791472
btck_BlockHeader* btck_block_header_create(const void* raw_block_header, size_t raw_block_header_len)

0 commit comments

Comments
 (0)