Skip to content

Commit 3916b85

Browse files
committed
Squashed 'libbitcoinkernel-sys/bitcoin/' changes from 5c5704e73079..7a9d79e26c8a
7a9d79e26c8a Add sans utxo set block validation 954181fb665b block header 5988c7172406 doc: Add docstrings for ConnectBlock and SpendBlock 72e4253794b4 validation: Move coin existence and spend check to SpendBlock 49c1e616c6f2 validation: Move SetBestBlock out of ConnectBlock a846a3838a3d validation: Add SpendBlock function 29c0068d8c12 validation: Use vector of outputs instead of CCoinsViewCache in CheckInputScripts ec04bb9d4b24 consensus: Use Coin span in CheckTxInputs 3d3c37bf599e consensus: Use Coin span in GetTransactionSigOpCost 193e81a6329e consensus: Use Coin span in GetP2SHSigOpCount git-subtree-dir: libbitcoinkernel-sys/bitcoin git-subtree-split: 7a9d79e26c8ab372761fb9a151a4eedbe6c392fc
1 parent d134c5d commit 3916b85

21 files changed

+902
-224
lines changed

libbitcoinkernel-sys/bitcoin/src/bench/connectblock.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <script/interpreter.h>
1010
#include <sync.h>
1111
#include <test/util/setup_common.h>
12+
#include <undo.h>
1213
#include <validation.h>
1314

1415
#include <cassert>
@@ -100,7 +101,9 @@ void BenchmarkConnectBlock(benchmark::Bench& bench, std::vector<CKey>& keys, std
100101
auto* pindex{chainman->m_blockman.AddToBlockIndex(test_block, chainman->m_best_header)}; // Doing this here doesn't impact the benchmark
101102
CCoinsViewCache viewNew{&chainstate.CoinsTip()};
102103

103-
assert(chainstate.ConnectBlock(test_block, test_block_state, pindex, viewNew));
104+
CBlockUndo blockundo;
105+
assert(chainstate.SpendBlock(test_block, pindex, viewNew, test_block_state, blockundo));
106+
assert(chainstate.ConnectBlock(test_block, blockundo, test_block_state, pindex));
104107
});
105108
}
106109

libbitcoinkernel-sys/bitcoin/src/bitcoin-chainstate.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class TestValidationInterface : public ValidationInterface
4444

4545
std::optional<std::string> m_expected_valid_block = std::nullopt;
4646

47-
void BlockChecked(const Block block, const BlockValidationState state) override
47+
void BlockChecked(const Block block, const BlockValidationStateView state) override
4848
{
4949
auto mode{state.GetValidationMode()};
5050
switch (mode) {

libbitcoinkernel-sys/bitcoin/src/coins.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,29 @@ const Coin& CCoinsViewCache::AccessCoin(const COutPoint &outpoint) const {
163163
}
164164
}
165165

166+
std::vector<std::reference_wrapper<const Coin>> CCoinsViewCache::AccessCoins(const CTransaction& tx) const
167+
{
168+
std::vector<std::reference_wrapper<const Coin>> coins;
169+
coins.reserve(tx.vin.size());
170+
for (const CTxIn& input : tx.vin) {
171+
coins.emplace_back(AccessCoin(input.prevout));
172+
}
173+
return coins;
174+
}
175+
176+
std::vector<CTxOut> CCoinsViewCache::GetUnspentOutputs(const CTransaction& tx) const
177+
{
178+
std::vector<CTxOut> spent_outputs;
179+
spent_outputs.reserve(tx.vin.size());
180+
for (const auto& txin : tx.vin) {
181+
const COutPoint& prevout = txin.prevout;
182+
const Coin& coin = AccessCoin(prevout);
183+
assert(!coin.IsSpent());
184+
spent_outputs.emplace_back(coin.out);
185+
}
186+
return spent_outputs;
187+
}
188+
166189
bool CCoinsViewCache::HaveCoin(const COutPoint &outpoint) const {
167190
CCoinsMap::const_iterator it = FetchCoin(outpoint);
168191
return (it != cacheCoins.end() && !it->second.coin.IsSpent());

libbitcoinkernel-sys/bitcoin/src/coins.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,22 @@ class CCoinsViewCache : public CCoinsViewBacked
413413
*/
414414
const Coin& AccessCoin(const COutPoint &output) const;
415415

416+
/**
417+
* Return a vector of references to Coins in the cache, or coinEmpty if
418+
* the Coin is not found.
419+
*
420+
* Generally, this should only be held for a short scope. The coins should
421+
* generally not be held through any other calls to this cache.
422+
*/
423+
std::vector<std::reference_wrapper<const Coin>> AccessCoins(const CTransaction& tx) const;
424+
425+
/**
426+
* Return a vector of unspent outputs of coins in the cache that are spent
427+
* by the provided transaction. The coins they belong to must be unspent in
428+
* the cache.
429+
*/
430+
std::vector<CTxOut> GetUnspentOutputs(const CTransaction& tx) const;
431+
416432
/**
417433
* Add a coin. Set possible_overwrite to true if an unspent version may
418434
* already exist in the cache.

libbitcoinkernel-sys/bitcoin/src/consensus/tx_verify.cpp

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include <util/check.h>
1515
#include <util/moneystr.h>
1616

17+
#include <span>
18+
1719
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
1820
{
1921
if (tx.nLockTime == 0)
@@ -123,62 +125,73 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx)
123125
return nSigOps;
124126
}
125127

126-
unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs)
128+
template <Consensus::CoinRef T>
129+
unsigned int GetP2SHSigOpCount(const CTransaction& tx, const std::span<T> coins)
127130
{
128131
if (tx.IsCoinBase())
129132
return 0;
130133

131134
unsigned int nSigOps = 0;
132-
for (unsigned int i = 0; i < tx.vin.size(); i++)
133-
{
134-
const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout);
135+
Assert(coins.size() == tx.vin.size());
136+
auto input_it = tx.vin.begin();
137+
for (auto it = coins.begin(); it != coins.end(); ++it, ++input_it) {
138+
const Coin& coin = *it;
135139
assert(!coin.IsSpent());
136140
const CTxOut &prevout = coin.out;
137141
if (prevout.scriptPubKey.IsPayToScriptHash())
138-
nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig);
142+
nSigOps += prevout.scriptPubKey.GetSigOpCount(input_it->scriptSig);
139143
}
140144
return nSigOps;
141145
}
142146

143-
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, script_verify_flags flags)
147+
template unsigned int GetP2SHSigOpCount<const Coin>(
148+
const CTransaction& tx, const std::span<const Coin>);
149+
150+
template unsigned int GetP2SHSigOpCount<std::reference_wrapper<const Coin>>(
151+
const CTransaction& tx, const std::span<std::reference_wrapper<const Coin>>);
152+
153+
template <Consensus::CoinRef T>
154+
int64_t GetTransactionSigOpCost(const CTransaction& tx, const std::span<T> coins, script_verify_flags flags)
144155
{
145156
int64_t nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR;
146157

147158
if (tx.IsCoinBase())
148159
return nSigOps;
149160

150161
if (flags & SCRIPT_VERIFY_P2SH) {
151-
nSigOps += GetP2SHSigOpCount(tx, inputs) * WITNESS_SCALE_FACTOR;
162+
nSigOps += GetP2SHSigOpCount(tx, coins) * WITNESS_SCALE_FACTOR;
152163
}
153164

154-
for (unsigned int i = 0; i < tx.vin.size(); i++)
155-
{
156-
const Coin& coin = inputs.AccessCoin(tx.vin[i].prevout);
165+
Assert(coins.size() == tx.vin.size());
166+
auto input_it = tx.vin.begin();
167+
for (auto it = coins.begin(); it != coins.end(); ++it, ++input_it) {
168+
const Coin& coin = *it;
157169
assert(!coin.IsSpent());
158170
const CTxOut &prevout = coin.out;
159-
nSigOps += CountWitnessSigOps(tx.vin[i].scriptSig, prevout.scriptPubKey, &tx.vin[i].scriptWitness, flags);
171+
nSigOps += CountWitnessSigOps(input_it->scriptSig, prevout.scriptPubKey, &input_it->scriptWitness, flags);
160172
}
161173
return nSigOps;
162174
}
175+
template int64_t GetTransactionSigOpCost<const Coin>(
176+
const CTransaction& tx, std::span<const Coin> coins, script_verify_flags flags);
163177

164-
bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
165-
{
166-
// are the actual inputs available?
167-
if (!inputs.HaveInputs(tx)) {
168-
return state.Invalid(TxValidationResult::TX_MISSING_INPUTS, "bad-txns-inputs-missingorspent",
169-
strprintf("%s: inputs missing/spent", __func__));
170-
}
178+
template int64_t GetTransactionSigOpCost<std::reference_wrapper<const Coin>>(
179+
const CTransaction& tx, const std::span<std::reference_wrapper<const Coin>> coins, script_verify_flags flags);
171180

181+
template <Consensus::CoinRef T>
182+
bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const std::span<T> coins, int nSpendHeight, CAmount& txfee)
183+
{
172184
CAmount nValueIn = 0;
173-
for (unsigned int i = 0; i < tx.vin.size(); ++i) {
174-
const COutPoint &prevout = tx.vin[i].prevout;
175-
const Coin& coin = inputs.AccessCoin(prevout);
185+
Assert(coins.size() == tx.vin.size());
186+
auto input_it = tx.vin.begin();
187+
for (auto it = coins.begin(); it != coins.end(); ++it, ++input_it) {
188+
const Coin& coin = *it;
176189
assert(!coin.IsSpent());
177190

178191
// If prev is coinbase, check that it's matured
179192
if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) {
180193
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-premature-spend-of-coinbase",
181-
strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
194+
strprintf("tried to spend coinbase at depth %d", static_cast<int>(nSpendHeight - coin.nHeight)));
182195
}
183196

184197
// Check for negative or overflow input values
@@ -203,3 +216,9 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state,
203216
txfee = txfee_aux;
204217
return true;
205218
}
219+
220+
template bool Consensus::CheckTxInputs<const Coin>(
221+
const CTransaction& tx, TxValidationState& state, const std::span<const Coin> coins, int nSpendHeight, CAmount& txfee);
222+
223+
template bool Consensus::CheckTxInputs<std::reference_wrapper<const Coin>>(
224+
const CTransaction& tx, TxValidationState& state, const std::span<std::reference_wrapper<const Coin>> coins, int nSpendHeight, CAmount& txfee);

libbitcoinkernel-sys/bitcoin/src/consensus/tx_verify.h

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
#ifndef BITCOIN_CONSENSUS_TX_VERIFY_H
66
#define BITCOIN_CONSENSUS_TX_VERIFY_H
77

8+
#include <coins.h>
89
#include <consensus/amount.h>
910
#include <script/verify_flags.h>
1011

12+
#include <concepts>
1113
#include <cstdint>
14+
#include <span>
1215
#include <vector>
1316

1417
class CBlockIndex;
@@ -19,13 +22,19 @@ class TxValidationState;
1922
/** Transaction validation functions */
2023

2124
namespace Consensus {
25+
26+
template <typename T>
27+
concept CoinRef = std::convertible_to<T, const Coin&>;
28+
2229
/**
23-
* Check whether all inputs of this transaction are valid (no double spends and amounts)
30+
* Check whether all inputs of this transaction are valid (amounts and maturity)
2431
* This does not modify the UTXO set. This does not check scripts and sigs.
32+
* @param[in] coins Sorted span of Coins containing previous transaction outputs tx is spending
2533
* @param[out] txfee Set to the transaction fee if successful.
2634
* Preconditions: tx.IsCoinBase() is false.
2735
*/
28-
[[nodiscard]] bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee);
36+
template <Consensus::CoinRef T>
37+
[[nodiscard]] bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const std::span<T> coins, int nSpendHeight, CAmount& txfee);
2938
} // namespace Consensus
3039

3140
/** Auxiliary functions for transaction validation (ideally should not be exposed) */
@@ -40,20 +49,22 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx);
4049
/**
4150
* Count ECDSA signature operations in pay-to-script-hash inputs.
4251
*
43-
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
52+
* @param[in] coins Sorted span of Coins containing previous transaction outputs we're spending
4453
* @return maximum number of sigops required to validate this transaction's inputs
4554
* @see CTransaction::FetchInputs
4655
*/
47-
unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& mapInputs);
56+
template <Consensus::CoinRef T>
57+
unsigned int GetP2SHSigOpCount(const CTransaction& tx, const std::span<T> coins);
4858

4959
/**
5060
* Compute total signature operation cost of a transaction.
51-
* @param[in] tx Transaction for which we are computing the cost
52-
* @param[in] inputs Map of previous transactions that have outputs we're spending
61+
* @param[in] tx Transaction for which we are computing the cost
62+
* @param[in] coins Sorted span of Coins containing previous transaction outputs we're spending
5363
* @param[in] flags Script verification flags
5464
* @return Total signature operation cost of tx
5565
*/
56-
int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& inputs, script_verify_flags flags);
66+
template <Consensus::CoinRef T>
67+
int64_t GetTransactionSigOpCost(const CTransaction& tx, const std::span<T> coins, script_verify_flags flags);
5768

5869
/**
5970
* Check if transaction is final and can be included in a block with the

0 commit comments

Comments
 (0)