|
|
@ -1492,12 +1492,13 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C |
|
|
|
|
|
|
|
|
|
|
|
// Check against previous transactions
|
|
|
|
// Check against previous transactions
|
|
|
|
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
|
|
|
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
|
|
|
if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true)) { |
|
|
|
CachedHashes cachedHashes(tx); |
|
|
|
|
|
|
|
if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, cachedHashes)) { |
|
|
|
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
|
|
|
|
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
|
|
|
|
// need to turn both off, and compare against just turning off CLEANSTACK
|
|
|
|
// need to turn both off, and compare against just turning off CLEANSTACK
|
|
|
|
// to see if the failure is specifically due to witness validation.
|
|
|
|
// to see if the failure is specifically due to witness validation.
|
|
|
|
if (CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true) && |
|
|
|
if (CheckInputs(tx, state, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, cachedHashes) && |
|
|
|
!CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true)) { |
|
|
|
!CheckInputs(tx, state, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, cachedHashes)) { |
|
|
|
// Only the witness is wrong, so the transaction itself may be fine.
|
|
|
|
// Only the witness is wrong, so the transaction itself may be fine.
|
|
|
|
state.SetCorruptionPossible(); |
|
|
|
state.SetCorruptionPossible(); |
|
|
|
} |
|
|
|
} |
|
|
@ -1513,7 +1514,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C |
|
|
|
// There is a similar check in CreateNewBlock() to prevent creating
|
|
|
|
// There is a similar check in CreateNewBlock() to prevent creating
|
|
|
|
// invalid blocks, however allowing such transactions into the mempool
|
|
|
|
// invalid blocks, however allowing such transactions into the mempool
|
|
|
|
// can be exploited as a DoS attack.
|
|
|
|
// can be exploited as a DoS attack.
|
|
|
|
if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true)) |
|
|
|
if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, cachedHashes)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s", |
|
|
|
return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s", |
|
|
|
__func__, hash.ToString(), FormatStateMessage(state)); |
|
|
|
__func__, hash.ToString(), FormatStateMessage(state)); |
|
|
@ -1910,7 +1911,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight) |
|
|
|
bool CScriptCheck::operator()() { |
|
|
|
bool CScriptCheck::operator()() { |
|
|
|
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; |
|
|
|
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; |
|
|
|
const CScriptWitness *witness = (nIn < ptxTo->wit.vtxinwit.size()) ? &ptxTo->wit.vtxinwit[nIn].scriptWitness : NULL; |
|
|
|
const CScriptWitness *witness = (nIn < ptxTo->wit.vtxinwit.size()) ? &ptxTo->wit.vtxinwit[nIn].scriptWitness : NULL; |
|
|
|
if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore), &error)) { |
|
|
|
if (!VerifyScript(scriptSig, scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *cachedHashes), &error)) { |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
return true; |
|
|
@ -1969,7 +1970,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins |
|
|
|
} |
|
|
|
} |
|
|
|
}// namespace Consensus
|
|
|
|
}// namespace Consensus
|
|
|
|
|
|
|
|
|
|
|
|
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks) |
|
|
|
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, CachedHashes& cachedHashes, std::vector<CScriptCheck> *pvChecks) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (!tx.IsCoinBase()) |
|
|
|
if (!tx.IsCoinBase()) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -1996,7 +1997,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi |
|
|
|
assert(coins); |
|
|
|
assert(coins); |
|
|
|
|
|
|
|
|
|
|
|
// Verify signature
|
|
|
|
// Verify signature
|
|
|
|
CScriptCheck check(*coins, tx, i, flags, cacheStore); |
|
|
|
CScriptCheck check(*coins, tx, i, flags, cacheStore, &cachedHashes); |
|
|
|
if (pvChecks) { |
|
|
|
if (pvChecks) { |
|
|
|
pvChecks->push_back(CScriptCheck()); |
|
|
|
pvChecks->push_back(CScriptCheck()); |
|
|
|
check.swap(pvChecks->back()); |
|
|
|
check.swap(pvChecks->back()); |
|
|
@ -2009,7 +2010,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi |
|
|
|
// avoid splitting the network between upgraded and
|
|
|
|
// avoid splitting the network between upgraded and
|
|
|
|
// non-upgraded nodes.
|
|
|
|
// non-upgraded nodes.
|
|
|
|
CScriptCheck check2(*coins, tx, i, |
|
|
|
CScriptCheck check2(*coins, tx, i, |
|
|
|
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore); |
|
|
|
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &cachedHashes); |
|
|
|
if (check2()) |
|
|
|
if (check2()) |
|
|
|
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); |
|
|
|
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError()))); |
|
|
|
} |
|
|
|
} |
|
|
@ -2405,6 +2406,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin |
|
|
|
std::vector<std::pair<uint256, CDiskTxPos> > vPos; |
|
|
|
std::vector<std::pair<uint256, CDiskTxPos> > vPos; |
|
|
|
vPos.reserve(block.vtx.size()); |
|
|
|
vPos.reserve(block.vtx.size()); |
|
|
|
blockundo.vtxundo.reserve(block.vtx.size() - 1); |
|
|
|
blockundo.vtxundo.reserve(block.vtx.size() - 1); |
|
|
|
|
|
|
|
std::vector<CachedHashes> cachedHashes; |
|
|
|
|
|
|
|
cachedHashes.reserve(block.vtx.size()); // Required so that pointers to individual CachedHashes don't get invalidated
|
|
|
|
for (unsigned int i = 0; i < block.vtx.size(); i++) |
|
|
|
for (unsigned int i = 0; i < block.vtx.size(); i++) |
|
|
|
{ |
|
|
|
{ |
|
|
|
const CTransaction &tx = block.vtx[i]; |
|
|
|
const CTransaction &tx = block.vtx[i]; |
|
|
@ -2451,13 +2454,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin |
|
|
|
return state.DoS(100, error("ConnectBlock(): too many sigops"), |
|
|
|
return state.DoS(100, error("ConnectBlock(): too many sigops"), |
|
|
|
REJECT_INVALID, "bad-blk-sigops"); |
|
|
|
REJECT_INVALID, "bad-blk-sigops"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cachedHashes.emplace_back(tx); |
|
|
|
if (!tx.IsCoinBase()) |
|
|
|
if (!tx.IsCoinBase()) |
|
|
|
{ |
|
|
|
{ |
|
|
|
nFees += view.GetValueIn(tx)-tx.GetValueOut(); |
|
|
|
nFees += view.GetValueIn(tx)-tx.GetValueOut(); |
|
|
|
|
|
|
|
|
|
|
|
std::vector<CScriptCheck> vChecks; |
|
|
|
std::vector<CScriptCheck> vChecks; |
|
|
|
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */ |
|
|
|
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */ |
|
|
|
if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, nScriptCheckThreads ? &vChecks : NULL)) |
|
|
|
if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, cachedHashes[i], nScriptCheckThreads ? &vChecks : NULL)) |
|
|
|
return error("ConnectBlock(): CheckInputs on %s failed with %s", |
|
|
|
return error("ConnectBlock(): CheckInputs on %s failed with %s", |
|
|
|
tx.GetHash().ToString(), FormatStateMessage(state)); |
|
|
|
tx.GetHash().ToString(), FormatStateMessage(state)); |
|
|
|
control.Add(vChecks); |
|
|
|
control.Add(vChecks); |
|
|
|