@@ -146,10 +146,10 @@ struct Handle {
146146
147147} // namespace
148148
149- struct btck_BlockTreeEntry : Handle<btck_BlockTreeEntry, CBlockIndex> {};
150149struct btck_Block : Handle<btck_Block, std::shared_ptr<const CBlock>> {};
151150struct btck_BlockValidationState : Handle<btck_BlockValidationState, BlockValidationState> {};
152151struct btck_TxValidationState : Handle<btck_TxValidationState, TxValidationState> {};
152+ struct btck_Chain : Handle<btck_Chain, CBlockIndex> {};
153153
154154namespace {
155155
@@ -303,7 +303,7 @@ class KernelNotifications final : public kernel::Notifications
303303
304304 kernel::InterruptResult blockTip (SynchronizationState state, const CBlockIndex& index, double verification_progress) override
305305 {
306- if (m_cbs.block_tip ) m_cbs.block_tip (m_cbs.user_data , cast_state (state), btck_BlockTreeEntry ::ref (&index), verification_progress);
306+ if (m_cbs.block_tip ) m_cbs.block_tip (m_cbs.user_data , cast_state (state), btck_Chain ::ref (&index), verification_progress);
307307 return {};
308308 }
309309 void headerTip (SynchronizationState state, int64_t height, int64_t timestamp, bool presync) override
@@ -363,7 +363,7 @@ class KernelValidationInterface final : public CValidationInterface
363363 if (m_cbs.pow_valid_block ) {
364364 m_cbs.pow_valid_block (m_cbs.user_data ,
365365 btck_Block::copy (btck_Block::ref (&block)),
366- btck_BlockTreeEntry ::ref (pindex));
366+ btck_Chain ::ref (pindex));
367367 }
368368 }
369369
@@ -372,7 +372,7 @@ class KernelValidationInterface final : public CValidationInterface
372372 if (m_cbs.block_connected ) {
373373 m_cbs.block_connected (m_cbs.user_data ,
374374 btck_Block::copy (btck_Block::ref (&block)),
375- btck_BlockTreeEntry ::ref (pindex));
375+ btck_Chain ::ref (pindex));
376376 }
377377 }
378378
@@ -381,7 +381,7 @@ class KernelValidationInterface final : public CValidationInterface
381381 if (m_cbs.block_disconnected ) {
382382 m_cbs.block_disconnected (m_cbs.user_data ,
383383 btck_Block::copy (btck_Block::ref (&block)),
384- btck_BlockTreeEntry ::ref (pindex));
384+ btck_Chain ::ref (pindex));
385385 }
386386 }
387387};
@@ -494,7 +494,6 @@ struct btck_Context : Handle<btck_Context, std::shared_ptr<const Context>> {};
494494struct btck_ChainParameters : Handle<btck_ChainParameters, CChainParams> {};
495495struct btck_ChainstateManagerOptions : Handle<btck_ChainstateManagerOptions, ChainstateManagerOptions> {};
496496struct btck_ChainstateManager : Handle<btck_ChainstateManager, ChainMan> {};
497- struct btck_Chain : Handle<btck_Chain, CChain> {};
498497struct btck_BlockSpentOutputs : Handle<btck_BlockSpentOutputs, std::shared_ptr<CBlockUndo>> {};
499498struct btck_TransactionSpentOutputs : Handle<btck_TransactionSpentOutputs, CTxUndo> {};
500499struct btck_Coin : Handle<btck_Coin, Coin> {};
@@ -895,23 +894,6 @@ void btck_context_destroy(btck_Context* context)
895894 delete context;
896895}
897896
898- const btck_BlockTreeEntry* btck_block_tree_entry_get_previous (const btck_BlockTreeEntry* entry)
899- {
900- if (!btck_BlockTreeEntry::get (entry).pprev ) {
901- LogInfo (" Genesis block has no previous." );
902- return nullptr ;
903- }
904-
905- return btck_BlockTreeEntry::ref (btck_BlockTreeEntry::get (entry).pprev );
906- }
907-
908- const btck_BlockTreeEntry* btck_block_tree_entry_get_ancestor (const btck_BlockTreeEntry* block_tree_entry, int32_t height)
909- {
910- const auto * ancestor{btck_BlockTreeEntry::get (block_tree_entry).GetAncestor (height)};
911- assert (ancestor);
912- return btck_BlockTreeEntry::ref (ancestor);
913- }
914-
915897btck_BlockValidationState* btck_block_validation_state_create ()
916898{
917899 return btck_BlockValidationState::create ();
@@ -1062,21 +1044,21 @@ btck_ChainstateManager* btck_chainstate_manager_create(
10621044 return btck_ChainstateManager::create (std::move (chainman), opts.m_context );
10631045}
10641046
1065- const btck_BlockTreeEntry* btck_chainstate_manager_get_block_tree_entry_by_hash (const btck_ChainstateManager* chainman, const btck_BlockHash* block_hash)
1047+ const btck_Chain* btck_chainstate_manager_find (const btck_ChainstateManager* chainman, const btck_BlockHash* block_hash)
10661048{
10671049 auto block_index = WITH_LOCK (btck_ChainstateManager::get (chainman).m_chainman ->GetMutex (),
10681050 return btck_ChainstateManager::get (chainman).m_chainman ->m_blockman .LookupBlockIndex (btck_BlockHash::get (block_hash)));
10691051 if (!block_index) {
10701052 LogDebug (BCLog::KERNEL , " A block with the given hash is not indexed." );
10711053 return nullptr ;
10721054 }
1073- return btck_BlockTreeEntry ::ref (block_index);
1055+ return btck_Chain ::ref (block_index);
10741056}
10751057
1076- const btck_BlockTreeEntry* btck_chainstate_manager_get_best_entry (const btck_ChainstateManager* chainstate_manager)
1058+ const btck_Chain* btck_chainstate_manager_get_best_chain (const btck_ChainstateManager* chainstate_manager)
10771059{
10781060 auto & chainman = *btck_ChainstateManager::get (chainstate_manager).m_chainman ;
1079- return btck_BlockTreeEntry ::ref (WITH_LOCK (chainman.GetMutex (), return chainman.m_best_header ));
1061+ return btck_Chain ::ref (WITH_LOCK (chainman.GetMutex (), return chainman.m_best_header ));
10801062}
10811063
10821064void btck_chainstate_manager_destroy (btck_ChainstateManager* chainman)
@@ -1186,36 +1168,20 @@ void btck_block_destroy(btck_Block* block)
11861168 delete block;
11871169}
11881170
1189- btck_Block* btck_block_read (const btck_ChainstateManager* chainman, const btck_BlockTreeEntry* entry )
1171+ btck_Block* btck_block_read (const btck_ChainstateManager* chainman, const btck_Chain* chain )
11901172{
1173+ if (!chain) {
1174+ LogDebug (BCLog::KERNEL , " The empty chain has no tip block to read." );
1175+ return nullptr ;
1176+ }
11911177 auto block{std::make_shared<CBlock>()};
1192- if (!btck_ChainstateManager::get (chainman).m_chainman ->m_blockman .ReadBlock (*block, btck_BlockTreeEntry ::get (entry ))) {
1178+ if (!btck_ChainstateManager::get (chainman).m_chainman ->m_blockman .ReadBlock (*block, btck_Chain ::get (chain ))) {
11931179 LogError (" Failed to read block." );
11941180 return nullptr ;
11951181 }
11961182 return btck_Block::create (block);
11971183}
11981184
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-
12191185btck_BlockHash* btck_block_hash_create (const unsigned char block_hash[32 ])
12201186{
12211187 return btck_BlockHash::create (std::span<const unsigned char >{block_hash, 32 });
@@ -1241,14 +1207,18 @@ void btck_block_hash_destroy(btck_BlockHash* hash)
12411207 delete hash;
12421208}
12431209
1244- btck_BlockSpentOutputs* btck_block_spent_outputs_read (const btck_ChainstateManager* chainman, const btck_BlockTreeEntry* entry )
1210+ btck_BlockSpentOutputs* btck_block_spent_outputs_read (const btck_ChainstateManager* chainman, const btck_Chain* chain )
12451211{
1212+ if (!chain) {
1213+ LogDebug (BCLog::KERNEL , " The empty chain has no tip block to read spent outputs for." );
1214+ return nullptr ;
1215+ }
12461216 auto block_undo{std::make_shared<CBlockUndo>()};
1247- if (btck_BlockTreeEntry ::get (entry ).nHeight < 1 ) {
1217+ if (btck_Chain ::get (chain ).nHeight == 0 ) {
12481218 LogDebug (BCLog::KERNEL , " The genesis block does not have any spent outputs." );
12491219 return btck_BlockSpentOutputs::create (block_undo);
12501220 }
1251- if (!btck_ChainstateManager::get (chainman).m_chainman ->m_blockman .ReadBlockUndo (*block_undo, btck_BlockTreeEntry ::get (entry ))) {
1221+ if (!btck_ChainstateManager::get (chainman).m_chainman ->m_blockman .ReadBlockUndo (*block_undo, btck_Chain ::get (chain ))) {
12521222 LogError (" Failed to read block spent outputs data." );
12531223 return nullptr ;
12541224 }
@@ -1355,25 +1325,83 @@ btck_BlockValidationState* btck_chainstate_manager_process_block_header(
13551325
13561326const btck_Chain* btck_chainstate_manager_get_active_chain (const btck_ChainstateManager* chainman)
13571327{
1358- return btck_Chain::ref (& WITH_LOCK (btck_ChainstateManager::get (chainman).m_chainman ->GetMutex (), return btck_ChainstateManager::get (chainman).m_chainman ->ActiveChain ()));
1328+ return btck_Chain::ref (WITH_LOCK (btck_ChainstateManager::get (chainman).m_chainman ->GetMutex (), return btck_ChainstateManager::get (chainman).m_chainman ->ActiveChain (). Tip ()));
13591329}
13601330
13611331int32_t btck_chain_get_height (const btck_Chain* chain)
13621332{
1363- LOCK (::cs_main);
1364- return btck_Chain::get (chain).Height () ;
1333+ // A null chain is the empty chain, which has no blocks and so a height of -1.
1334+ return chain ? btck_Chain::get (chain).nHeight : - 1 ;
13651335}
13661336
1367- const btck_BlockTreeEntry* btck_chain_get_by_height (const btck_Chain* chain, int32_t height)
1337+ btck_BlockHeader* btck_chain_get_block_header (const btck_Chain* chain, int32_t height)
13681338{
1369- LOCK (::cs_main);
1370- return btck_BlockTreeEntry::ref (btck_Chain::get (chain)[height]);
1339+ const auto * index{chain ? btck_Chain::get (chain).GetAncestor (height) : nullptr };
1340+ if (!index) {
1341+ LogDebug (BCLog::KERNEL , " The requested height is not in the chain." );
1342+ return nullptr ;
1343+ }
1344+ return btck_BlockHeader::create (index->GetBlockHeader ());
1345+ }
1346+
1347+ const btck_BlockHash* btck_chain_get_block_hash (const btck_Chain* chain, int32_t height)
1348+ {
1349+ const auto * index{chain ? btck_Chain::get (chain).GetAncestor (height) : nullptr };
1350+ if (!index) {
1351+ LogDebug (BCLog::KERNEL , " The requested height is not in the chain." );
1352+ return nullptr ;
1353+ }
1354+ return btck_BlockHash::ref (index->phashBlock );
1355+ }
1356+
1357+ const btck_Chain* btck_chain_get_ancestor (const btck_Chain* chain, int32_t height)
1358+ {
1359+ const auto * ancestor{chain ? btck_Chain::get (chain).GetAncestor (height) : nullptr };
1360+ if (!ancestor) {
1361+ LogDebug (BCLog::KERNEL , " The requested height is not in the chain." );
1362+ return nullptr ;
1363+ }
1364+ return btck_Chain::ref (ancestor);
1365+ }
1366+
1367+ const btck_Chain* btck_chain_get_parent (const btck_Chain* chain)
1368+ {
1369+ // The parent of the empty chain, and of the genesis-only chain, is the empty
1370+ // chain.
1371+ const auto * pprev{chain ? btck_Chain::get (chain).pprev : nullptr };
1372+ if (!pprev) {
1373+ return nullptr ;
1374+ }
1375+ return btck_Chain::ref (pprev);
1376+ }
1377+
1378+ int btck_chain_starts_with (const btck_Chain* chain, const btck_Chain* prefix)
1379+ {
1380+ // The empty chain is a prefix of every chain; a non-empty prefix cannot be a
1381+ // prefix of the empty chain.
1382+ if (!prefix) return 1 ;
1383+ if (!chain) return 0 ;
1384+ const auto & tip{btck_Chain::get (chain)};
1385+ const auto & prefix_tip{btck_Chain::get (prefix)};
1386+ return tip.GetAncestor (prefix_tip.nHeight ) == &prefix_tip ? 1 : 0 ;
1387+ }
1388+
1389+ const btck_Chain* btck_chain_find_fork (const btck_Chain* chain1, const btck_Chain* chain2)
1390+ {
1391+ // The empty chain shares no block with any chain, so the fork is empty.
1392+ if (!chain1 || !chain2) return nullptr ;
1393+ const auto * common{LastCommonAncestor (&btck_Chain::get (chain1), &btck_Chain::get (chain2))};
1394+ if (!common) {
1395+ return nullptr ;
1396+ }
1397+ return btck_Chain::ref (common);
13711398}
13721399
1373- int btck_chain_contains (const btck_Chain* chain , const btck_BlockTreeEntry* entry )
1400+ int btck_chain_equals (const btck_Chain* chain1 , const btck_Chain* chain2 )
13741401{
1375- LOCK (::cs_main);
1376- return btck_Chain::get (chain).Contains (btck_BlockTreeEntry::get (entry)) ? 1 : 0 ;
1402+ // Chains are identified by their tip, which a btck_Chain* aliases directly,
1403+ // so pointer equality is chain equality (and the empty chain equals itself).
1404+ return chain1 == chain2 ? 1 : 0 ;
13771405}
13781406
13791407btck_BlockHeader* btck_block_header_create (const void * raw_block_header, size_t raw_block_header_len)
0 commit comments