mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-22 15:04:44 +01:00
refactor: keep spent outputs in PrecomputedTransactionData
A BIP-341 signature message may commit to the scriptPubKeys and amounts of all spent outputs (including other ones than the input being signed for spends), so keep them available to signature hashing code.
This commit is contained in:
parent
8bd2b4e784
commit
5d62e3a68b
3 changed files with 22 additions and 11 deletions
|
@ -1294,10 +1294,12 @@ uint256 GetOutputsSHA256(const T& txTo)
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void PrecomputedTransactionData::Init(const T& txTo)
|
void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent_outputs)
|
||||||
{
|
{
|
||||||
assert(!m_ready);
|
assert(!m_ready);
|
||||||
|
|
||||||
|
m_spent_outputs = std::move(spent_outputs);
|
||||||
|
|
||||||
// Cache is calculated only for transactions with witness
|
// Cache is calculated only for transactions with witness
|
||||||
if (txTo.HasWitness()) {
|
if (txTo.HasWitness()) {
|
||||||
hashPrevouts = SHA256Uint256(GetPrevoutsSHA256(txTo));
|
hashPrevouts = SHA256Uint256(GetPrevoutsSHA256(txTo));
|
||||||
|
@ -1311,12 +1313,12 @@ void PrecomputedTransactionData::Init(const T& txTo)
|
||||||
template <class T>
|
template <class T>
|
||||||
PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo)
|
PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo)
|
||||||
{
|
{
|
||||||
Init(txTo);
|
Init(txTo, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
// explicit instantiation
|
// explicit instantiation
|
||||||
template void PrecomputedTransactionData::Init(const CTransaction& txTo);
|
template void PrecomputedTransactionData::Init(const CTransaction& txTo, std::vector<CTxOut>&& spent_outputs);
|
||||||
template void PrecomputedTransactionData::Init(const CMutableTransaction& txTo);
|
template void PrecomputedTransactionData::Init(const CMutableTransaction& txTo, std::vector<CTxOut>&& spent_outputs);
|
||||||
template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
|
template PrecomputedTransactionData::PrecomputedTransactionData(const CTransaction& txTo);
|
||||||
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
|
template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTransaction& txTo);
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
class CPubKey;
|
class CPubKey;
|
||||||
class CScript;
|
class CScript;
|
||||||
class CTransaction;
|
class CTransaction;
|
||||||
|
class CTxOut;
|
||||||
class uint256;
|
class uint256;
|
||||||
|
|
||||||
/** Signature hash types/flags */
|
/** Signature hash types/flags */
|
||||||
|
@ -122,11 +123,12 @@ struct PrecomputedTransactionData
|
||||||
{
|
{
|
||||||
uint256 hashPrevouts, hashSequence, hashOutputs;
|
uint256 hashPrevouts, hashSequence, hashOutputs;
|
||||||
bool m_ready = false;
|
bool m_ready = false;
|
||||||
|
std::vector<CTxOut> m_spent_outputs;
|
||||||
|
|
||||||
PrecomputedTransactionData() = default;
|
PrecomputedTransactionData() = default;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void Init(const T& tx);
|
void Init(const T& tx, std::vector<CTxOut>&& spent_outputs);
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
explicit PrecomputedTransactionData(const T& tx);
|
explicit PrecomputedTransactionData(const T& tx);
|
||||||
|
|
|
@ -1539,13 +1539,20 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!txdata.m_ready) {
|
if (!txdata.m_ready) {
|
||||||
txdata.Init(tx);
|
std::vector<CTxOut> spent_outputs;
|
||||||
|
spent_outputs.reserve(tx.vin.size());
|
||||||
|
|
||||||
|
for (const auto& txin : tx.vin) {
|
||||||
|
const COutPoint& prevout = txin.prevout;
|
||||||
|
const Coin& coin = inputs.AccessCoin(prevout);
|
||||||
|
assert(!coin.IsSpent());
|
||||||
|
spent_outputs.emplace_back(coin.out);
|
||||||
|
}
|
||||||
|
txdata.Init(tx, std::move(spent_outputs));
|
||||||
}
|
}
|
||||||
|
assert(txdata.m_spent_outputs.size() == tx.vin.size());
|
||||||
|
|
||||||
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
||||||
const COutPoint &prevout = tx.vin[i].prevout;
|
|
||||||
const Coin& coin = inputs.AccessCoin(prevout);
|
|
||||||
assert(!coin.IsSpent());
|
|
||||||
|
|
||||||
// We very carefully only pass in things to CScriptCheck which
|
// We very carefully only pass in things to CScriptCheck which
|
||||||
// are clearly committed to by tx' witness hash. This provides
|
// are clearly committed to by tx' witness hash. This provides
|
||||||
|
@ -1554,7 +1561,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C
|
||||||
// spent being checked as a part of CScriptCheck.
|
// spent being checked as a part of CScriptCheck.
|
||||||
|
|
||||||
// Verify signature
|
// Verify signature
|
||||||
CScriptCheck check(coin.out, tx, i, flags, cacheSigStore, &txdata);
|
CScriptCheck check(txdata.m_spent_outputs[i], tx, i, flags, cacheSigStore, &txdata);
|
||||||
if (pvChecks) {
|
if (pvChecks) {
|
||||||
pvChecks->push_back(CScriptCheck());
|
pvChecks->push_back(CScriptCheck());
|
||||||
check.swap(pvChecks->back());
|
check.swap(pvChecks->back());
|
||||||
|
@ -1568,7 +1575,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C
|
||||||
// splitting the network between upgraded and
|
// splitting the network between upgraded and
|
||||||
// non-upgraded nodes by banning CONSENSUS-failing
|
// non-upgraded nodes by banning CONSENSUS-failing
|
||||||
// data providers.
|
// data providers.
|
||||||
CScriptCheck check2(coin.out, tx, i,
|
CScriptCheck check2(txdata.m_spent_outputs[i], tx, i,
|
||||||
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata);
|
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata);
|
||||||
if (check2())
|
if (check2())
|
||||||
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
|
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
|
||||||
|
|
Loading…
Add table
Reference in a new issue