|
|
|
@ -14,6 +14,7 @@
|
|
|
|
|
#include "consensus/merkle.h"
|
|
|
|
|
#include "consensus/tx_verify.h"
|
|
|
|
|
#include "consensus/validation.h"
|
|
|
|
|
#include "cuckoocache.h"
|
|
|
|
|
#include "fs.h"
|
|
|
|
|
#include "hash.h"
|
|
|
|
|
#include "init.h"
|
|
|
|
@ -189,7 +190,7 @@ enum FlushStateMode {
|
|
|
|
|
static bool FlushStateToDisk(const CChainParams& chainParams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight=0);
|
|
|
|
|
static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight);
|
|
|
|
|
static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight);
|
|
|
|
|
static bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = NULL);
|
|
|
|
|
static bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr);
|
|
|
|
|
static FILE* OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false);
|
|
|
|
|
|
|
|
|
|
bool CheckFinalTx(const CTransaction &tx, int flags)
|
|
|
|
@ -752,29 +753,36 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
|
|
|
|
|
// Check against previous transactions
|
|
|
|
|
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
|
|
|
|
PrecomputedTransactionData txdata(tx);
|
|
|
|
|
if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, txdata)) {
|
|
|
|
|
if (!CheckInputs(tx, state, view, true, scriptVerifyFlags, true, false, txdata)) {
|
|
|
|
|
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
|
|
|
|
|
// need to turn both off, and compare against just turning off CLEANSTACK
|
|
|
|
|
// to see if the failure is specifically due to witness validation.
|
|
|
|
|
CValidationState stateDummy; // Want reported failures to be from first CheckInputs
|
|
|
|
|
if (!tx.HasWitness() && CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, txdata) &&
|
|
|
|
|
!CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, txdata)) {
|
|
|
|
|
if (!tx.HasWitness() && CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, txdata) &&
|
|
|
|
|
!CheckInputs(tx, stateDummy, view, true, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) {
|
|
|
|
|
// Only the witness is missing, so the transaction itself may be fine.
|
|
|
|
|
state.SetCorruptionPossible();
|
|
|
|
|
}
|
|
|
|
|
return false; // state filled in by CheckInputs
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check again against just the consensus-critical mandatory script
|
|
|
|
|
// verification flags, in case of bugs in the standard flags that cause
|
|
|
|
|
// Check again against the current block tip's script verification
|
|
|
|
|
// flags to cache our script execution flags. This is, of course,
|
|
|
|
|
// useless if the next block has different script flags from the
|
|
|
|
|
// previous one, but because the cache tracks script flags for us it
|
|
|
|
|
// will auto-invalidate and we'll just have a few blocks of extra
|
|
|
|
|
// misses on soft-fork activation.
|
|
|
|
|
//
|
|
|
|
|
// This is also useful in case of bugs in the standard flags that cause
|
|
|
|
|
// transactions to pass as valid when they're actually invalid. For
|
|
|
|
|
// instance the STRICTENC flag was incorrectly allowing certain
|
|
|
|
|
// CHECKSIG NOT scripts to pass, even though they were invalid.
|
|
|
|
|
//
|
|
|
|
|
// There is a similar check in CreateNewBlock() to prevent creating
|
|
|
|
|
// invalid blocks, however allowing such transactions into the mempool
|
|
|
|
|
// can be exploited as a DoS attack.
|
|
|
|
|
if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, txdata))
|
|
|
|
|
// invalid blocks (using TestBlockValidity), however allowing such
|
|
|
|
|
// transactions into the mempool can be exploited as a DoS attack.
|
|
|
|
|
unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(chainActive.Tip(), Params().GetConsensus());
|
|
|
|
|
if (!CheckInputs(tx, state, view, true, currentBlockScriptVerifyFlags, true, true, txdata))
|
|
|
|
|
{
|
|
|
|
|
return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s",
|
|
|
|
|
__func__, hash.ToString(), FormatStateMessage(state));
|
|
|
|
@ -1152,12 +1160,25 @@ int GetSpendHeight(const CCoinsViewCache& inputs)
|
|
|
|
|
return pindexPrev->nHeight + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static CuckooCache::cache<uint256, SignatureCacheHasher> scriptExecutionCache;
|
|
|
|
|
static uint256 scriptExecutionCacheNonce(GetRandHash());
|
|
|
|
|
|
|
|
|
|
void InitScriptExecutionCache() {
|
|
|
|
|
// nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero,
|
|
|
|
|
// setup_bytes creates the minimum possible cache (2 elements).
|
|
|
|
|
size_t nMaxCacheSize = std::min(std::max((int64_t)0, GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) / 2), MAX_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
|
|
|
|
|
size_t nElems = scriptExecutionCache.setup_bytes(nMaxCacheSize);
|
|
|
|
|
LogPrintf("Using %zu MiB out of %zu requested for script execution cache, able to store %zu elements\n",
|
|
|
|
|
(nElems*sizeof(uint256)) >>20, nMaxCacheSize>>20, nElems);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
|
|
|
|
|
* This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
|
|
|
|
|
* instead of being performed inline.
|
|
|
|
|
*/
|
|
|
|
|
static bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks)
|
|
|
|
|
static bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks)
|
|
|
|
|
{
|
|
|
|
|
if (!tx.IsCoinBase())
|
|
|
|
|
{
|
|
|
|
@ -1177,6 +1198,21 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
|
|
|
|
|
// Of course, if an assumed valid block is invalid due to false scriptSigs
|
|
|
|
|
// this optimization would allow an invalid chain to be accepted.
|
|
|
|
|
if (fScriptChecks) {
|
|
|
|
|
// First check if script executions have been cached with the same
|
|
|
|
|
// flags. Note that this assumes that the inputs provided are
|
|
|
|
|
// correct (ie that the transaction hash which is in tx's prevouts
|
|
|
|
|
// properly commits to the scriptPubKey in the inputs view of that
|
|
|
|
|
// transaction).
|
|
|
|
|
uint256 hashCacheEntry;
|
|
|
|
|
// We only use the first 19 bytes of nonce to avoid a second SHA
|
|
|
|
|
// round - giving us 19 + 32 + 4 = 55 bytes (+ 8 + 1 = 64)
|
|
|
|
|
static_assert(55 - sizeof(flags) - 32 >= 128/8, "Want at least 128 bits of nonce for script execution cache");
|
|
|
|
|
CSHA256().Write(scriptExecutionCacheNonce.begin(), 55 - sizeof(flags) - 32).Write(tx.GetWitnessHash().begin(), 32).Write((unsigned char*)&flags, sizeof(flags)).Finalize(hashCacheEntry.begin());
|
|
|
|
|
AssertLockHeld(cs_main); //TODO: Remove this requirement by making CuckooCache not require external locks
|
|
|
|
|
if (scriptExecutionCache.contains(hashCacheEntry, !cacheFullScriptStore)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
|
|
|
|
const COutPoint &prevout = tx.vin[i].prevout;
|
|
|
|
|
const Coin& coin = inputs.AccessCoin(prevout);
|
|
|
|
@ -1191,7 +1227,7 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
|
|
|
|
|
const CAmount amount = coin.out.nValue;
|
|
|
|
|
|
|
|
|
|
// Verify signature
|
|
|
|
|
CScriptCheck check(scriptPubKey, amount, tx, i, flags, cacheStore, &txdata);
|
|
|
|
|
CScriptCheck check(scriptPubKey, amount, tx, i, flags, cacheSigStore, &txdata);
|
|
|
|
|
if (pvChecks) {
|
|
|
|
|
pvChecks->push_back(CScriptCheck());
|
|
|
|
|
check.swap(pvChecks->back());
|
|
|
|
@ -1204,7 +1240,7 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
|
|
|
|
|
// avoid splitting the network between upgraded and
|
|
|
|
|
// non-upgraded nodes.
|
|
|
|
|
CScriptCheck check2(scriptPubKey, amount, tx, i,
|
|
|
|
|
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore, &txdata);
|
|
|
|
|
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata);
|
|
|
|
|
if (check2())
|
|
|
|
|
return state.Invalid(false, REJECT_NONSTANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
|
|
|
|
|
}
|
|
|
|
@ -1218,6 +1254,12 @@ static bool CheckInputs(const CTransaction& tx, CValidationState &state, const C
|
|
|
|
|
return state.DoS(100,false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cacheFullScriptStore && !pvChecks) {
|
|
|
|
|
// We executed all of the provided scripts, and were told to
|
|
|
|
|
// cache the result. Do so now.
|
|
|
|
|
scriptExecutionCache.insert(hashCacheEntry);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1684,7 +1726,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
|
|
|
|
|
|
|
|
|
|
std::vector<CScriptCheck> vChecks;
|
|
|
|
|
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, txdata[i], nScriptCheckThreads ? &vChecks : NULL))
|
|
|
|
|
if (!CheckInputs(tx, state, view, fScriptChecks, flags, fCacheResults, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : NULL))
|
|
|
|
|
return error("ConnectBlock(): CheckInputs on %s failed with %s",
|
|
|
|
|
tx.GetHash().ToString(), FormatStateMessage(state));
|
|
|
|
|
control.Add(vChecks);
|
|
|
|
|