Skip to content

Commit f5d5d12

Browse files
committed
kernel: Add function to read block undo data from disk to C header
This adds functions for reading the undo data from disk with a retrieved block tree entry. The undo data of a block contains all the spent script pubkeys of all the transactions in a block. For ease of understanding the undo data is renamed to spent outputs with seperate data structures exposed for a block's and a transaction's spent outputs. In normal operations undo data is used during re-orgs. This data might also be useful for building external indexes, or to scan for silent payment transactions. Internally the block undo data contains a vector of transaction undo data which contains a vector of the coins consumed. The coins are all int the order of the transaction inputs of the consuming transactions. Each coin can be used to retrieve a transaction output and in turn a script pubkey and amount. This translates to the three-level hierarchy the api provides: Block spent outputs contain transaction spent outputs, which contain individual coins. Each coin includes the associated output, the height of the block is contained in, and whether it is from a coinbase transaction.
1 parent 09d0f62 commit f5d5d12

File tree

4 files changed

+420
-4
lines changed

4 files changed

+420
-4
lines changed

src/kernel/bitcoinkernel.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <kernel/bitcoinkernel.h>
88

99
#include <chain.h>
10+
#include <coins.h>
1011
#include <consensus/amount.h>
1112
#include <consensus/validation.h>
1213
#include <kernel/caches.h>
@@ -28,6 +29,7 @@
2829
#include <sync.h>
2930
#include <tinyformat.h>
3031
#include <uint256.h>
32+
#include <undo.h>
3133
#include <util/fs.h>
3234
#include <util/result.h>
3335
#include <util/signalinterrupt.h>
@@ -485,6 +487,9 @@ struct btck_ChainParameters : Handle<btck_ChainParameters, CChainParams> {};
485487
struct btck_ChainstateManagerOptions : Handle<btck_ChainstateManagerOptions, ChainstateManagerOptions> {};
486488
struct btck_ChainstateManager : Handle<btck_ChainstateManager, ChainMan> {};
487489
struct btck_Chain : Handle<btck_Chain, CChain> {};
490+
struct btck_BlockSpentOutputs : Handle<btck_BlockSpentOutputs, std::shared_ptr<CBlockUndo>> {};
491+
struct btck_TransactionSpentOutputs : Handle<btck_TransactionSpentOutputs, CTxUndo> {};
492+
struct btck_Coin : Handle<btck_Coin, Coin> {};
488493

489494
btck_Transaction* btck_transaction_create(const void* raw_transaction, size_t raw_transaction_len)
490495
{
@@ -1004,6 +1009,89 @@ btck_Block* btck_block_read(const btck_ChainstateManager* chainman, const btck_B
10041009
return btck_Block::create(block);
10051010
}
10061011

1012+
btck_BlockSpentOutputs* btck_block_spent_outputs_read(const btck_ChainstateManager* chainman, const btck_BlockTreeEntry* entry)
1013+
{
1014+
auto block_undo{std::make_shared<CBlockUndo>()};
1015+
if (btck_BlockTreeEntry::get(entry).nHeight < 1) {
1016+
LogDebug(BCLog::KERNEL, "The genesis block does not have any spent outputs.");
1017+
return btck_BlockSpentOutputs::create(block_undo);
1018+
}
1019+
if (!btck_ChainstateManager::get(chainman).m_chainman->m_blockman.ReadBlockUndo(*block_undo, btck_BlockTreeEntry::get(entry))) {
1020+
LogError("Failed to read block spent outputs data.");
1021+
return nullptr;
1022+
}
1023+
return btck_BlockSpentOutputs::create(block_undo);
1024+
}
1025+
1026+
btck_BlockSpentOutputs* btck_block_spent_outputs_copy(const btck_BlockSpentOutputs* block_spent_outputs)
1027+
{
1028+
return btck_BlockSpentOutputs::copy(block_spent_outputs);
1029+
}
1030+
1031+
size_t btck_block_spent_outputs_count(const btck_BlockSpentOutputs* block_spent_outputs)
1032+
{
1033+
return btck_BlockSpentOutputs::get(block_spent_outputs)->vtxundo.size();
1034+
}
1035+
1036+
const btck_TransactionSpentOutputs* btck_block_spent_outputs_get_transaction_spent_outputs_at(const btck_BlockSpentOutputs* block_spent_outputs, size_t transaction_index)
1037+
{
1038+
assert(transaction_index < btck_BlockSpentOutputs::get(block_spent_outputs)->vtxundo.size());
1039+
const auto* tx_undo{&btck_BlockSpentOutputs::get(block_spent_outputs)->vtxundo.at(transaction_index)};
1040+
return btck_TransactionSpentOutputs::ref(tx_undo);
1041+
}
1042+
1043+
void btck_block_spent_outputs_destroy(btck_BlockSpentOutputs* block_spent_outputs)
1044+
{
1045+
delete block_spent_outputs;
1046+
}
1047+
1048+
btck_TransactionSpentOutputs* btck_transaction_spent_outputs_copy(const btck_TransactionSpentOutputs* transaction_spent_outputs)
1049+
{
1050+
return btck_TransactionSpentOutputs::copy(transaction_spent_outputs);
1051+
}
1052+
1053+
size_t btck_transaction_spent_outputs_count(const btck_TransactionSpentOutputs* transaction_spent_outputs)
1054+
{
1055+
return btck_TransactionSpentOutputs::get(transaction_spent_outputs).vprevout.size();
1056+
}
1057+
1058+
void btck_transaction_spent_outputs_destroy(btck_TransactionSpentOutputs* transaction_spent_outputs)
1059+
{
1060+
delete transaction_spent_outputs;
1061+
}
1062+
1063+
const btck_Coin* btck_transaction_spent_outputs_get_coin_at(const btck_TransactionSpentOutputs* transaction_spent_outputs, size_t coin_index)
1064+
{
1065+
assert(coin_index < btck_TransactionSpentOutputs::get(transaction_spent_outputs).vprevout.size());
1066+
const Coin* coin{&btck_TransactionSpentOutputs::get(transaction_spent_outputs).vprevout.at(coin_index)};
1067+
return btck_Coin::ref(coin);
1068+
}
1069+
1070+
btck_Coin* btck_coin_copy(const btck_Coin* coin)
1071+
{
1072+
return btck_Coin::copy(coin);
1073+
}
1074+
1075+
uint32_t btck_coin_confirmation_height(const btck_Coin* coin)
1076+
{
1077+
return btck_Coin::get(coin).nHeight;
1078+
}
1079+
1080+
int btck_coin_is_coinbase(const btck_Coin* coin)
1081+
{
1082+
return btck_Coin::get(coin).IsCoinBase() ? 1 : 0;
1083+
}
1084+
1085+
const btck_TransactionOutput* btck_coin_get_output(const btck_Coin* coin)
1086+
{
1087+
return btck_TransactionOutput::ref(&btck_Coin::get(coin).out);
1088+
}
1089+
1090+
void btck_coin_destroy(btck_Coin* coin)
1091+
{
1092+
delete coin;
1093+
}
1094+
10071095
int btck_chainstate_manager_process_block(
10081096
btck_ChainstateManager* chainman,
10091097
const btck_Block* block,

src/kernel/bitcoinkernel.h

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,36 @@ typedef struct btck_BlockValidationState btck_BlockValidationState;
212212
*/
213213
typedef struct btck_Chain btck_Chain;
214214

215+
/**
216+
* Opaque data structure for holding a block's spent outputs.
217+
*
218+
* Contains all the previous outputs consumed by all transactions in a specific
219+
* block. Internally it holds a nested vector. The top level vector has an
220+
* entry for each transaction in a block (in order of the actual transactions
221+
* of the block and without the coinbase transaction). This is exposed through
222+
* @ref btck_TransactionSpentOutputs. Each btck_TransactionSpentOutputs is in
223+
* turn a vector of all the previous outputs of a transaction (in order of
224+
* their corresponding inputs).
225+
*/
226+
typedef struct btck_BlockSpentOutputs btck_BlockSpentOutputs;
227+
228+
/**
229+
* Opaque data structure for holding a transaction's spent outputs.
230+
*
231+
* Holds the coins consumed by a certain transaction. Retrieved through the
232+
* @ref btck_BlockSpentOutputs. The coins are in the same order as the
233+
* transaction's inputs consuming them.
234+
*/
235+
typedef struct btck_TransactionSpentOutputs btck_TransactionSpentOutputs;
236+
237+
/**
238+
* Opaque data structure for holding a coin.
239+
*
240+
* Holds information on the @ref btck_TransactionOutput held within,
241+
* including the height it was spent at and whether it is a coinbase output.
242+
*/
243+
typedef struct btck_Coin btck_Coin;
244+
215245
/** Current sync state passed to tip changed callbacks. */
216246
typedef uint8_t btck_SynchronizationState;
217247
#define btck_SynchronizationState_INIT_REINDEX ((btck_SynchronizationState)(0))
@@ -1102,6 +1132,156 @@ BITCOINKERNEL_API int32_t BITCOINKERNEL_WARN_UNUSED_RESULT btck_chain_get_height
11021132

11031133
///@}
11041134

1135+
/** @name BlockSpentOutputs
1136+
* Functions for working with block spent outputs.
1137+
*/
1138+
///@{
1139+
1140+
/**
1141+
* @brief Reads the block spent coins data the passed in block tree entry points to from
1142+
* disk and returns it.
1143+
*
1144+
* @param[in] chainstate_manager Non-null.
1145+
* @param[in] block_tree_entry Non-null.
1146+
* @return The read out block spent outputs, or null on error.
1147+
*/
1148+
BITCOINKERNEL_API btck_BlockSpentOutputs* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_spent_outputs_read(
1149+
const btck_ChainstateManager* chainstate_manager,
1150+
const btck_BlockTreeEntry* block_tree_entry) BITCOINKERNEL_ARG_NONNULL(1, 2);
1151+
1152+
/**
1153+
* @brief Copy a block's spent outputs.
1154+
*
1155+
* @param[in] block_spent_outputs Non-null.
1156+
* @return The copied block spent outputs.
1157+
*/
1158+
BITCOINKERNEL_API btck_BlockSpentOutputs* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_spent_outputs_copy(
1159+
const btck_BlockSpentOutputs* block_spent_outputs) BITCOINKERNEL_ARG_NONNULL(1);
1160+
1161+
/**
1162+
* @brief Returns the number of transaction spent outputs whose data is contained in
1163+
* block spent outputs.
1164+
*
1165+
* @param[in] block_spent_outputs Non-null.
1166+
* @return The number of transaction spent outputs data in the block spent outputs.
1167+
*/
1168+
BITCOINKERNEL_API size_t BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_spent_outputs_count(
1169+
const btck_BlockSpentOutputs* block_spent_outputs) BITCOINKERNEL_ARG_NONNULL(1);
1170+
1171+
/**
1172+
* @brief Returns a transaction spent outputs contained in the block spent
1173+
* outputs at a certain index. The returned pointer is unowned and only valid
1174+
* for the lifetime of block_spent_outputs.
1175+
*
1176+
* @param[in] block_spent_outputs Non-null.
1177+
* @param[in] transaction_spent_outputs_index The index of the transaction spent outputs within the block spent outputs.
1178+
* @return A transaction spent outputs pointer.
1179+
*/
1180+
BITCOINKERNEL_API const btck_TransactionSpentOutputs* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_spent_outputs_get_transaction_spent_outputs_at(
1181+
const btck_BlockSpentOutputs* block_spent_outputs,
1182+
size_t transaction_spent_outputs_index) BITCOINKERNEL_ARG_NONNULL(1);
1183+
1184+
/**
1185+
* Destroy the block spent outputs.
1186+
*/
1187+
BITCOINKERNEL_API void btck_block_spent_outputs_destroy(btck_BlockSpentOutputs* block_spent_outputs);
1188+
1189+
///@}
1190+
1191+
/** @name TransactionSpentOutputs
1192+
* Functions for working with the spent coins of a transaction
1193+
*/
1194+
///@{
1195+
1196+
/**
1197+
* @brief Copy a transaction's spent outputs.
1198+
*
1199+
* @param[in] transaction_spent_outputs Non-null.
1200+
* @return The copied transaction spent outputs.
1201+
*/
1202+
BITCOINKERNEL_API btck_TransactionSpentOutputs* BITCOINKERNEL_WARN_UNUSED_RESULT btck_transaction_spent_outputs_copy(
1203+
const btck_TransactionSpentOutputs* transaction_spent_outputs) BITCOINKERNEL_ARG_NONNULL(1);
1204+
1205+
/**
1206+
* @brief Returns the number of previous transaction outputs contained in the
1207+
* transaction spent outputs data.
1208+
*
1209+
* @param[in] transaction_spent_outputs Non-null
1210+
* @return The number of spent transaction outputs for the transaction.
1211+
*/
1212+
BITCOINKERNEL_API size_t BITCOINKERNEL_WARN_UNUSED_RESULT btck_transaction_spent_outputs_count(
1213+
const btck_TransactionSpentOutputs* transaction_spent_outputs) BITCOINKERNEL_ARG_NONNULL(1);
1214+
1215+
/**
1216+
* @brief Returns a coin contained in the transaction spent outputs at a
1217+
* certain index. The returned pointer is unowned and only valid for the
1218+
* lifetime of transaction_spent_outputs.
1219+
*
1220+
* @param[in] transaction_spent_outputs Non-null.
1221+
* @param[in] coin_index The index of the to be retrieved coin within the
1222+
* transaction spent outputs.
1223+
* @return A coin pointer.
1224+
*/
1225+
BITCOINKERNEL_API const btck_Coin* BITCOINKERNEL_WARN_UNUSED_RESULT btck_transaction_spent_outputs_get_coin_at(
1226+
const btck_TransactionSpentOutputs* transaction_spent_outputs,
1227+
size_t coin_index) BITCOINKERNEL_ARG_NONNULL(1);
1228+
1229+
/**
1230+
* Destroy the transaction spent outputs.
1231+
*/
1232+
BITCOINKERNEL_API void btck_transaction_spent_outputs_destroy(btck_TransactionSpentOutputs* transaction_spent_outputs);
1233+
1234+
///@}
1235+
1236+
/** @name Coin
1237+
* Functions for working with coins.
1238+
*/
1239+
///@{
1240+
1241+
/**
1242+
* @brief Copy a coin.
1243+
*
1244+
* @param[in] coin Non-null.
1245+
* @return The copied coin.
1246+
*/
1247+
BITCOINKERNEL_API btck_Coin* BITCOINKERNEL_WARN_UNUSED_RESULT btck_coin_copy(
1248+
const btck_Coin* coin) BITCOINKERNEL_ARG_NONNULL(1);
1249+
1250+
/**
1251+
* @brief Returns the height of the block that contains the coin's prevout.
1252+
*
1253+
* @param[in] coin Non-null.
1254+
* @return The block height of the coin.
1255+
*/
1256+
BITCOINKERNEL_API uint32_t BITCOINKERNEL_WARN_UNUSED_RESULT btck_coin_confirmation_height(
1257+
const btck_Coin* coin) BITCOINKERNEL_ARG_NONNULL(1);
1258+
1259+
/**
1260+
* @brief Returns whether the containing transaction was a coinbase.
1261+
*
1262+
* @param[in] coin Non-null.
1263+
* @return 1 if the coin is a coinbase coin, 0 otherwise.
1264+
*/
1265+
BITCOINKERNEL_API int BITCOINKERNEL_WARN_UNUSED_RESULT btck_coin_is_coinbase(
1266+
const btck_Coin* coin) BITCOINKERNEL_ARG_NONNULL(1);
1267+
1268+
/**
1269+
* @brief Return the transaction output of a coin. The returned pointer is
1270+
* unowned and only valid for the lifetime of the coin.
1271+
*
1272+
* @param[in] coin Non-null.
1273+
* @return A transaction output pointer.
1274+
*/
1275+
BITCOINKERNEL_API const btck_TransactionOutput* BITCOINKERNEL_WARN_UNUSED_RESULT btck_coin_get_output(
1276+
const btck_Coin* coin) BITCOINKERNEL_ARG_NONNULL(1);
1277+
1278+
/**
1279+
* Destroy the coin.
1280+
*/
1281+
BITCOINKERNEL_API void btck_coin_destroy(btck_Coin* coin);
1282+
1283+
///@}
1284+
11051285
#ifdef __cplusplus
11061286
} // extern "C"
11071287
#endif // __cplusplus

0 commit comments

Comments
 (0)