mirror of https://github.com/bitcoin/bitcoin.git
Kernel: Add functions for working with outpoints
This introduces the transaction outpoint, input and id types. This now allows a user to retrieve a transaction output from a prior transaction that a transaction outpoint is pointing to. This is exercised in the tests by verifying the script of every transaction in the test chain.
This commit is contained in:
parent
00000cb55a
commit
7918a4d17d
|
@ -498,6 +498,9 @@ struct btck_BlockSpentOutputs : Handle<btck_BlockSpentOutputs, std::shared_ptr<C
|
|||
struct btck_TransactionSpentOutputs : Handle<btck_TransactionSpentOutputs, CTxUndo> {};
|
||||
struct btck_Coin : Handle<btck_Coin, Coin> {};
|
||||
struct btck_BlockHash : Handle<btck_BlockHash, uint256> {};
|
||||
struct btck_TransactionInput : Handle<btck_TransactionInput, CTxIn> {};
|
||||
struct btck_TransactionOutPoint: Handle<btck_TransactionOutPoint, COutPoint> {};
|
||||
struct btck_Txid: Handle<btck_Txid, Txid> {};
|
||||
|
||||
btck_Transaction* btck_transaction_create(const void* raw_transaction, size_t raw_transaction_len)
|
||||
{
|
||||
|
@ -526,6 +529,17 @@ size_t btck_transaction_count_inputs(const btck_Transaction* transaction)
|
|||
return btck_Transaction::get(transaction)->vin.size();
|
||||
}
|
||||
|
||||
const btck_TransactionInput* btck_transaction_get_input_at(const btck_Transaction* transaction, size_t input_index)
|
||||
{
|
||||
assert(input_index < btck_Transaction::get(transaction)->vin.size());
|
||||
return btck_TransactionInput::ref(&btck_Transaction::get(transaction)->vin[input_index]);
|
||||
}
|
||||
|
||||
const btck_Txid* btck_transaction_get_txid(const btck_Transaction* transaction)
|
||||
{
|
||||
return btck_Txid::ref(&btck_Transaction::get(transaction)->GetHash());
|
||||
}
|
||||
|
||||
btck_Transaction* btck_transaction_copy(const btck_Transaction* transaction)
|
||||
{
|
||||
return btck_Transaction::copy(transaction);
|
||||
|
@ -642,6 +656,61 @@ int btck_script_pubkey_verify(const btck_ScriptPubkey* script_pubkey,
|
|||
return result ? 1 : 0;
|
||||
}
|
||||
|
||||
btck_TransactionInput* btck_transaction_input_copy(const btck_TransactionInput* input)
|
||||
{
|
||||
return btck_TransactionInput::copy(input);
|
||||
}
|
||||
|
||||
const btck_TransactionOutPoint* btck_transaction_input_get_out_point(const btck_TransactionInput* input)
|
||||
{
|
||||
return btck_TransactionOutPoint::ref(&btck_TransactionInput::get(input).prevout);
|
||||
}
|
||||
|
||||
void btck_transaction_input_destroy(btck_TransactionInput* input)
|
||||
{
|
||||
delete input;
|
||||
}
|
||||
|
||||
btck_TransactionOutPoint* btck_transaction_out_point_copy(const btck_TransactionOutPoint* out_point)
|
||||
{
|
||||
return btck_TransactionOutPoint::copy(out_point);
|
||||
}
|
||||
|
||||
uint32_t btck_transaction_out_point_get_index(const btck_TransactionOutPoint* out_point)
|
||||
{
|
||||
return btck_TransactionOutPoint::get(out_point).n;
|
||||
}
|
||||
|
||||
const btck_Txid* btck_transaction_out_point_get_txid(const btck_TransactionOutPoint* out_point)
|
||||
{
|
||||
return btck_Txid::ref(&btck_TransactionOutPoint::get(out_point).hash);
|
||||
}
|
||||
|
||||
void btck_transaction_out_point_destroy(btck_TransactionOutPoint* out_point)
|
||||
{
|
||||
delete out_point;
|
||||
}
|
||||
|
||||
btck_Txid* btck_txid_copy(const btck_Txid* txid)
|
||||
{
|
||||
return btck_Txid::copy(txid);
|
||||
}
|
||||
|
||||
void btck_txid_to_bytes(const btck_Txid* txid, unsigned char output[32])
|
||||
{
|
||||
std::memcpy(output, btck_Txid::get(txid).begin(), 32);
|
||||
}
|
||||
|
||||
int btck_txid_equals(const btck_Txid* txid1, const btck_Txid* txid2)
|
||||
{
|
||||
return btck_Txid::get(txid1) == btck_Txid::get(txid2);
|
||||
}
|
||||
|
||||
void btck_txid_destroy(btck_Txid* txid)
|
||||
{
|
||||
delete txid;
|
||||
}
|
||||
|
||||
void btck_logging_set_level_category(btck_LogCategory category, btck_LogLevel level)
|
||||
{
|
||||
LOCK(cs_main);
|
||||
|
|
|
@ -248,6 +248,22 @@ typedef struct btck_Coin btck_Coin;
|
|||
*/
|
||||
typedef struct btck_BlockHash btck_BlockHash;
|
||||
|
||||
/**
|
||||
* Opaque data structure for holding a transaction input.
|
||||
*
|
||||
* Holds information on the @ref btck_TransactionOutPoint held within.
|
||||
*/
|
||||
typedef struct btck_TransactionInput btck_TransactionInput;
|
||||
|
||||
/**
|
||||
* Opaque data structure for holding a transaction out point.
|
||||
*
|
||||
* Holds the transaction id and output index it is pointing to.
|
||||
*/
|
||||
typedef struct btck_TransactionOutPoint btck_TransactionOutPoint;
|
||||
|
||||
typedef struct btck_Txid btck_Txid;
|
||||
|
||||
/** Current sync state passed to tip changed callbacks. */
|
||||
typedef uint8_t btck_SynchronizationState;
|
||||
#define btck_SynchronizationState_INIT_REINDEX ((btck_SynchronizationState)(0))
|
||||
|
@ -493,6 +509,18 @@ BITCOINKERNEL_API size_t BITCOINKERNEL_WARN_UNUSED_RESULT btck_transaction_count
|
|||
BITCOINKERNEL_API const btck_TransactionOutput* BITCOINKERNEL_WARN_UNUSED_RESULT btck_transaction_get_output_at(
|
||||
const btck_Transaction* transaction, size_t output_index) BITCOINKERNEL_ARG_NONNULL(1);
|
||||
|
||||
/**
|
||||
* @brief Get the transaction input at the provided index. The returned
|
||||
* transaction input is not owned and depends on the lifetime of the
|
||||
* transaction.
|
||||
*
|
||||
* @param[in] transaction Non-null.
|
||||
* @param[in] input_index The index of the transaction input to be retrieved.
|
||||
* @return The transaction input
|
||||
*/
|
||||
BITCOINKERNEL_API const btck_TransactionInput* BITCOINKERNEL_WARN_UNUSED_RESULT btck_transaction_get_input_at(
|
||||
const btck_Transaction* transaction, size_t input_index) BITCOINKERNEL_ARG_NONNULL(1);
|
||||
|
||||
/**
|
||||
* @brief Get the number of inputs of a transaction.
|
||||
*
|
||||
|
@ -502,6 +530,15 @@ BITCOINKERNEL_API const btck_TransactionOutput* BITCOINKERNEL_WARN_UNUSED_RESULT
|
|||
BITCOINKERNEL_API size_t BITCOINKERNEL_WARN_UNUSED_RESULT btck_transaction_count_inputs(
|
||||
const btck_Transaction* transaction) BITCOINKERNEL_ARG_NONNULL(1);
|
||||
|
||||
/**
|
||||
* @brief Get the txid of a transaction.
|
||||
*
|
||||
* @param[in] transaction Non-null.
|
||||
* @return The txid.
|
||||
*/
|
||||
BITCOINKERNEL_API const btck_Txid* BITCOINKERNEL_WARN_UNUSED_RESULT btck_transaction_get_txid(
|
||||
const btck_Transaction* transaction) BITCOINKERNEL_ARG_NONNULL(1);
|
||||
|
||||
/**
|
||||
* Destroy the transaction.
|
||||
*/
|
||||
|
@ -1292,6 +1329,118 @@ BITCOINKERNEL_API void btck_transaction_spent_outputs_destroy(btck_TransactionSp
|
|||
|
||||
///@}
|
||||
|
||||
/** @name Transaction Input
|
||||
* Functions for working with transaction inputs.
|
||||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Copy a transaction input.
|
||||
*
|
||||
* @param[in] transaction_input Non-null.
|
||||
* @return The copied transaction input.
|
||||
*/
|
||||
BITCOINKERNEL_API btck_TransactionInput* BITCOINKERNEL_WARN_UNUSED_RESULT btck_transaction_input_copy(
|
||||
const btck_TransactionInput* transaction_input) BITCOINKERNEL_ARG_NONNULL(1);
|
||||
|
||||
/**
|
||||
* @brief Get the transaction out point. The returned transaction out point is
|
||||
* not owned and depends on the lifetime of the transaction.
|
||||
*
|
||||
* @param[in] transaction_input Non-null.
|
||||
* @return The transaction out point.
|
||||
*/
|
||||
BITCOINKERNEL_API const btck_TransactionOutPoint* BITCOINKERNEL_WARN_UNUSED_RESULT btck_transaction_input_get_out_point(
|
||||
const btck_TransactionInput* transaction_input) BITCOINKERNEL_ARG_NONNULL(1);
|
||||
|
||||
/**
|
||||
* Destroy the transaction input.
|
||||
*/
|
||||
BITCOINKERNEL_API void btck_transaction_input_destroy(btck_TransactionInput* transaction_input);
|
||||
|
||||
///@}
|
||||
|
||||
/** @name Transaction Out Point
|
||||
* Functions for working with transaction out points.
|
||||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Copy a transaction out point.
|
||||
*
|
||||
* @param[in] transaction_out_point Non-null.
|
||||
* @return The copied transaction out point.
|
||||
*/
|
||||
BITCOINKERNEL_API btck_TransactionOutPoint* BITCOINKERNEL_WARN_UNUSED_RESULT btck_transaction_out_point_copy(
|
||||
const btck_TransactionOutPoint* transaction_out_point) BITCOINKERNEL_ARG_NONNULL(1);
|
||||
|
||||
/**
|
||||
* @brief Get the output position from the out point.
|
||||
*
|
||||
* @param[in] transaction_out_point Non-null.
|
||||
* @return The output index.
|
||||
*/
|
||||
BITCOINKERNEL_API uint32_t btck_transaction_out_point_get_index(
|
||||
const btck_TransactionOutPoint* transaction_out_point) BITCOINKERNEL_ARG_NONNULL(1);
|
||||
|
||||
/**
|
||||
* @brief Get the txid from the out point.
|
||||
*
|
||||
* @param[in] transaction_out_point Non-null.
|
||||
* @return The txid.
|
||||
*/
|
||||
BITCOINKERNEL_API const btck_Txid* btck_transaction_out_point_get_txid(
|
||||
const btck_TransactionOutPoint* transaction_out_point) BITCOINKERNEL_ARG_NONNULL(1);
|
||||
|
||||
/**
|
||||
* Destroy the transaction out point.
|
||||
*/
|
||||
BITCOINKERNEL_API void btck_transaction_out_point_destroy(btck_TransactionOutPoint* transaction_out_point);
|
||||
|
||||
///@}
|
||||
|
||||
/** @name Txid
|
||||
* Functions for working with txids.
|
||||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* @brief Copy a txid.
|
||||
*
|
||||
* @param[in] txid Non-null.
|
||||
* @return The copied txid.
|
||||
*/
|
||||
BITCOINKERNEL_API btck_Txid* BITCOINKERNEL_WARN_UNUSED_RESULT btck_txid_copy(
|
||||
const btck_Txid* txid) BITCOINKERNEL_ARG_NONNULL(1);
|
||||
|
||||
/**
|
||||
* @brief Check if two txids are equal.
|
||||
*
|
||||
* @param[in] txid1 Non-null.
|
||||
* @param[in] txid2 Non-null.
|
||||
* @return 0 if the txid is not equal.
|
||||
*/
|
||||
BITCOINKERNEL_API int btck_txid_equals(
|
||||
const btck_Txid* txid1, const btck_Txid* txid2) BITCOINKERNEL_ARG_NONNULL(1, 2);
|
||||
|
||||
/**
|
||||
* @brief Serializes the txid to bytes.
|
||||
*
|
||||
* @param[in] txid Non-null.
|
||||
* @param[out] output The serialized txid.
|
||||
*/
|
||||
BITCOINKERNEL_API void btck_txid_to_bytes(
|
||||
const btck_Txid* txid, unsigned char output[32]) BITCOINKERNEL_ARG_NONNULL(1, 2);
|
||||
|
||||
/**
|
||||
* Destroy the txid.
|
||||
*/
|
||||
BITCOINKERNEL_API void btck_txid_destroy(btck_Txid* txid);
|
||||
|
||||
///@}
|
||||
|
||||
///@}
|
||||
|
||||
/** @name Coin
|
||||
* Functions for working with coins.
|
||||
*/
|
||||
|
|
|
@ -447,6 +447,119 @@ public:
|
|||
: Handle(view) {}
|
||||
};
|
||||
|
||||
template <typename Derived>
|
||||
class TxidApi
|
||||
{
|
||||
private:
|
||||
auto impl() const
|
||||
{
|
||||
return static_cast<const Derived*>(this)->get();
|
||||
}
|
||||
|
||||
friend Derived;
|
||||
TxidApi() = default;
|
||||
|
||||
public:
|
||||
bool operator==(const TxidApi& other) const
|
||||
{
|
||||
return btck_txid_equals(impl(), other.impl()) != 0;
|
||||
}
|
||||
|
||||
bool operator!=(const TxidApi& other) const
|
||||
{
|
||||
return btck_txid_equals(impl(), other.impl()) == 0;
|
||||
}
|
||||
|
||||
std::array<std::byte, 32> ToBytes() const
|
||||
{
|
||||
std::array<std::byte, 32> hash;
|
||||
btck_txid_to_bytes(impl(), reinterpret_cast<unsigned char*>(hash.data()));
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
class TxidView : public View<btck_Txid>, public TxidApi<TxidView>
|
||||
{
|
||||
public:
|
||||
explicit TxidView(const btck_Txid* ptr) : View{ptr} {}
|
||||
};
|
||||
|
||||
class Txid : public Handle<btck_Txid, btck_txid_copy, btck_txid_destroy>, public TxidApi<Txid>
|
||||
{
|
||||
public:
|
||||
Txid(const TxidView& view)
|
||||
: Handle(view) {}
|
||||
};
|
||||
|
||||
template <typename Derived>
|
||||
class OutPointApi
|
||||
{
|
||||
private:
|
||||
auto impl() const
|
||||
{
|
||||
return static_cast<const Derived*>(this)->get();
|
||||
}
|
||||
|
||||
friend Derived;
|
||||
OutPointApi() = default;
|
||||
|
||||
public:
|
||||
uint32_t index() const
|
||||
{
|
||||
return btck_transaction_out_point_get_index(impl());
|
||||
}
|
||||
|
||||
TxidView Txid() const
|
||||
{
|
||||
return TxidView{btck_transaction_out_point_get_txid(impl())};
|
||||
}
|
||||
};
|
||||
|
||||
class OutPointView : public View<btck_TransactionOutPoint>, public OutPointApi<OutPointView>
|
||||
{
|
||||
public:
|
||||
explicit OutPointView(const btck_TransactionOutPoint* ptr) : View{ptr} {}
|
||||
};
|
||||
|
||||
class OutPoint : public Handle<btck_TransactionOutPoint, btck_transaction_out_point_copy, btck_transaction_out_point_destroy>, public OutPointApi<OutPoint>
|
||||
{
|
||||
public:
|
||||
OutPoint(const OutPointView& view)
|
||||
: Handle(view) {}
|
||||
};
|
||||
|
||||
template <typename Derived>
|
||||
class TransactionInputApi
|
||||
{
|
||||
private:
|
||||
auto impl() const
|
||||
{
|
||||
return static_cast<const Derived*>(this)->get();
|
||||
}
|
||||
|
||||
friend Derived;
|
||||
TransactionInputApi() = default;
|
||||
|
||||
public:
|
||||
OutPointView OutPoint() const
|
||||
{
|
||||
return OutPointView{btck_transaction_input_get_out_point(impl())};
|
||||
}
|
||||
};
|
||||
|
||||
class TransactionInputView : public View<btck_TransactionInput>, public TransactionInputApi<TransactionInputView>
|
||||
{
|
||||
public:
|
||||
explicit TransactionInputView(const btck_TransactionInput* ptr) : View{ptr} {}
|
||||
};
|
||||
|
||||
class TransactionInput : public Handle<btck_TransactionInput, btck_transaction_input_copy, btck_transaction_input_destroy>, public TransactionInputApi<TransactionInput>
|
||||
{
|
||||
public:
|
||||
TransactionInput(const TransactionInputView& view)
|
||||
: Handle(view) {}
|
||||
};
|
||||
|
||||
template <typename Derived>
|
||||
class TransactionApi
|
||||
{
|
||||
|
@ -472,11 +585,26 @@ public:
|
|||
return TransactionOutputView{btck_transaction_get_output_at(impl(), index)};
|
||||
}
|
||||
|
||||
TransactionInputView GetInput(size_t index) const
|
||||
{
|
||||
return TransactionInputView{btck_transaction_get_input_at(impl(), index)};
|
||||
}
|
||||
|
||||
TxidView Txid() const
|
||||
{
|
||||
return TxidView{btck_transaction_get_txid(impl())};
|
||||
}
|
||||
|
||||
auto Outputs() const
|
||||
{
|
||||
return Range<Derived, &TransactionApi<Derived>::CountOutputs, &TransactionApi<Derived>::GetOutput>{*static_cast<const Derived*>(this)};
|
||||
}
|
||||
|
||||
auto Inputs() const
|
||||
{
|
||||
return Range<Derived, &TransactionApi<Derived>::CountInputs, &TransactionApi<Derived>::GetInput>{*static_cast<const Derived*>(this)};
|
||||
}
|
||||
|
||||
std::vector<std::byte> ToBytes() const
|
||||
{
|
||||
return write_bytes(impl(), btck_transaction_to_bytes);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
@ -61,6 +62,19 @@ std::vector<std::byte> hex_string_to_byte_vec(std::string_view hex)
|
|||
return bytes;
|
||||
}
|
||||
|
||||
std::string byte_span_to_hex_string_reversed(std::span<const std::byte> bytes)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
// Iterate in reverse order
|
||||
for (auto it = bytes.rbegin(); it != bytes.rend(); ++it) {
|
||||
oss << std::hex << std::setw(2) << std::setfill('0')
|
||||
<< static_cast<unsigned int>(static_cast<uint8_t>(*it));
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
constexpr auto VERIFY_ALL_PRE_SEGWIT{ScriptVerificationFlags::P2SH | ScriptVerificationFlags::DERSIG |
|
||||
ScriptVerificationFlags::NULLDUMMY | ScriptVerificationFlags::CHECKLOCKTIMEVERIFY |
|
||||
ScriptVerificationFlags::CHECKSEQUENCEVERIFY};
|
||||
|
@ -476,6 +490,18 @@ BOOST_AUTO_TEST_CASE(btck_transaction_output)
|
|||
CheckHandle(output, output2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(btck_transaction_input)
|
||||
{
|
||||
Transaction tx{hex_string_to_byte_vec("020000000248c03e66fd371c7033196ce24298628e59ebefa00363026044e0f35e0325a65d000000006a473044022004893432347f39beaa280e99da595681ddb20fc45010176897e6e055d716dbfa022040a9e46648a5d10c33ef7cee5e6cf4b56bd513eae3ae044f0039824b02d0f44c012102982331a52822fd9b62e9b5d120da1d248558fac3da3a3c51cd7d9c8ad3da760efeffffffb856678c6e4c3c84e39e2ca818807049d6fba274b42af3c6d3f9d4b6513212d2000000006a473044022068bcedc7fe39c9f21ad318df2c2da62c2dc9522a89c28c8420ff9d03d2e6bf7b0220132afd752754e5cb1ea2fd0ed6a38ec666781e34b0e93dc9a08f2457842cf5660121033aeb9c079ea3e08ea03556182ab520ce5c22e6b0cb95cee6435ee17144d860cdfeffffff0260d50b00000000001976a914363cc8d55ea8d0500de728ef6d63804ddddbdc9888ac67040f00000000001976a914c303bdc5064bf9c9a8b507b5496bd0987285707988ac6acb0700")};
|
||||
TransactionInput input_0 = tx.GetInput(0);
|
||||
TransactionInput input_1 = tx.GetInput(1);
|
||||
CheckHandle(input_0, input_1);
|
||||
CheckRange(tx.Inputs(), tx.CountInputs());
|
||||
OutPoint point_0 = input_0.OutPoint();
|
||||
OutPoint point_1 = input_1.OutPoint();
|
||||
CheckHandle(point_0, point_1);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(btck_script_verify_tests)
|
||||
{
|
||||
// Legacy transaction aca326a724eda9a461c10a876534ecd5ae7b27f10f26c3862fb996f80ea2d45d
|
||||
|
@ -731,6 +757,7 @@ void chainman_mainnet_validation_test(TestDirectory& test_directory)
|
|||
auto raw_block = hex_string_to_byte_vec("010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e362990101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000");
|
||||
Block block{raw_block};
|
||||
TransactionView tx{block.GetTransaction(block.CountTransactions() - 1)};
|
||||
BOOST_CHECK_EQUAL(byte_span_to_hex_string_reversed(tx.Txid().ToBytes()), "0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098");
|
||||
BOOST_CHECK_EQUAL(tx.CountInputs(), 1);
|
||||
Transaction tx2 = tx;
|
||||
BOOST_CHECK_EQUAL(tx2.CountInputs(), 1);
|
||||
|
@ -869,6 +896,48 @@ BOOST_AUTO_TEST_CASE(btck_chainman_regtest_tests)
|
|||
auto read_block_2 = chainman->ReadBlock(tip_2).value();
|
||||
check_equal(read_block_2.ToBytes(), as_bytes(REGTEST_BLOCK_DATA[REGTEST_BLOCK_DATA.size() - 2]));
|
||||
|
||||
Txid txid = read_block.Transactions()[0].Txid();
|
||||
Txid txid_2 = read_block_2.Transactions()[0].Txid();
|
||||
BOOST_CHECK(txid != txid_2);
|
||||
BOOST_CHECK(txid == txid);
|
||||
CheckHandle(txid, txid_2);
|
||||
|
||||
auto find_transaction = [&chainman](const TxidView& target_txid) -> std::optional<Transaction> {
|
||||
for (const auto block_tree_entry : chainman->GetChain().Entries()) {
|
||||
auto block{chainman->ReadBlock(block_tree_entry)};
|
||||
for (const auto transaction : block->Transactions()) {
|
||||
if (transaction.Txid() == target_txid) {
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
};
|
||||
|
||||
for (const auto block_tree_entry : chainman->GetChain().Entries()) {
|
||||
auto block{chainman->ReadBlock(block_tree_entry)};
|
||||
for (const auto transaction : block->Transactions()) {
|
||||
std::vector<TransactionInput> inputs;
|
||||
std::vector<TransactionOutput> spent_outputs;
|
||||
for (const auto input : transaction.Inputs()) {
|
||||
OutPointView point = input.OutPoint();
|
||||
if (point.index() == std::numeric_limits<uint32_t>::max()) {
|
||||
continue;
|
||||
}
|
||||
inputs.emplace_back(input);
|
||||
BOOST_CHECK(point.Txid() != transaction.Txid());
|
||||
Transaction tx = *find_transaction(point.Txid());
|
||||
BOOST_CHECK(point.Txid() == tx.Txid());
|
||||
spent_outputs.emplace_back(tx.GetOutput(point.index()));
|
||||
}
|
||||
BOOST_CHECK(inputs.size() == spent_outputs.size());
|
||||
ScriptVerifyStatus status = ScriptVerifyStatus::OK;
|
||||
for (size_t i{0}; i < inputs.size(); ++i) {
|
||||
BOOST_CHECK(spent_outputs[i].GetScriptPubkey().Verify(spent_outputs[i].Amount(), transaction, spent_outputs, i, ScriptVerificationFlags::ALL, status));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BlockSpentOutputs block_spent_outputs{chainman->ReadBlockSpentOutputs(tip)};
|
||||
BlockSpentOutputs block_spent_outputs_prev{chainman->ReadBlockSpentOutputs(*tip.GetPrevious())};
|
||||
CheckHandle(block_spent_outputs, block_spent_outputs_prev);
|
||||
|
|
Loading…
Reference in New Issue