@@ -1092,7 +1092,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
10921092
10931093 // Check against previous transactions
10941094 // This is done last to help prevent CPU exhaustion denial-of-service attacks.
1095- if (!CheckInputs (tx, state, view, true , STANDARD_SCRIPT_VERIFY_FLAGS , true ))
1095+ if (!CheckInputs (tx, state, view, true , STANDARD_SCRIPT_VERIFY_FLAGS , true , NULL ))
10961096 {
10971097 return error (" AcceptToMemoryPool: ConnectInputs failed %s" , hash.ToString ());
10981098 }
@@ -1106,7 +1106,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
11061106 // There is a similar check in CreateNewBlock() to prevent creating
11071107 // invalid blocks, however allowing such transactions into the mempool
11081108 // can be exploited as a DoS attack.
1109- if (!CheckInputs (tx, state, view, true , MANDATORY_SCRIPT_VERIFY_FLAGS , true ))
1109+ if (!CheckInputs (tx, state, view, true , MANDATORY_SCRIPT_VERIFY_FLAGS , true , NULL ))
11101110 {
11111111 return error (" AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s" , hash.ToString ());
11121112 }
@@ -1445,14 +1445,23 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
14451445}
14461446
14471447bool CScriptCheck::operator ()() {
1448+ if (costTracker && !costTracker->IsWithinLimits ())
1449+ return false ; // Don't do any more checks if already past limits
1450+
14481451 const CScript &scriptSig = ptxTo->vin [nIn].scriptSig ;
1449- if (!VerifyScript (scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker (ptxTo, nIn, cacheStore), &error)) {
1452+ CachingTransactionSignatureChecker checker (ptxTo, nIn, cacheStore);
1453+ if (!VerifyScript (scriptSig, scriptPubKey, nFlags, checker, &error)) {
14501454 return ::error (" CScriptCheck(): %s:%d VerifySignature failed: %s" , ptxTo->GetHash ().ToString (), nIn, ScriptErrorString (error));
14511455 }
1456+ if (costTracker) {
1457+ if (!costTracker->Update (ptxTo->GetHash (), checker.GetNumSigops (), checker.GetBytesHashed ()))
1458+ return ::error (" CScriptCheck(): %s:%d sigop and/or sighash byte limit exceeded" ,
1459+ ptxTo->GetHash ().ToString (), nIn);
1460+ }
14521461 return true ;
14531462}
14541463
1455- bool CheckInputs (const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks , unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks)
1464+ bool CheckInputs (const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks , unsigned int flags, bool cacheStore, ValidationCostTracker* costTracker, std::vector<CScriptCheck> *pvChecks)
14561465{
14571466 if (!tx.IsCoinBase ())
14581467 {
@@ -1521,7 +1530,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
15211530 assert (coins);
15221531
15231532 // Verify signature
1524- CScriptCheck check (*coins, tx, i, flags, cacheStore);
1533+ CScriptCheck check (costTracker, *coins, tx, i, flags, cacheStore);
15251534 if (pvChecks) {
15261535 pvChecks->push_back (CScriptCheck ());
15271536 check.swap (pvChecks->back ());
@@ -1533,7 +1542,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
15331542 // arguments; if so, don't trigger DoS protection to
15341543 // avoid splitting the network between upgraded and
15351544 // non-upgraded nodes.
1536- CScriptCheck check (*coins, tx, i,
1545+ CScriptCheck check (NULL , *coins, tx, i,
15371546 flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS , cacheStore);
15381547 if (check ())
15391548 return state.Invalid (false , REJECT_NONSTANDARD , strprintf (" non-mandatory-script-verify-flag (%s)" , ScriptErrorString (check.GetScriptError ())));
@@ -1906,12 +1915,18 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
19061915
19071916 CBlockUndo blockundo;
19081917
1918+ int64_t nTimeStart = GetTimeMicros ();
1919+
1920+ // Pre-fork, legacy sigop counting is used, unlimited resource tracker
1921+ // Post-fork, accurately counted sigop/sighash limits are used
1922+ ValidationCostTracker costTracker (MaxBlockSigops (block.nTime ), MaxBlockSighash (block.nTime ));
1923+
19091924 CCheckQueueControl<CScriptCheck> control (fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL );
19101925
1911- int64_t nTimeStart = GetTimeMicros ();
19121926 CAmount nFees = 0 ;
19131927 int nInputs = 0 ;
1914- unsigned int nSigOps = 0 ;
1928+ uint32_t nSigOps = 0 ;
1929+ uint32_t nMaxLegacySigops = MaxLegacySigops (block.nTime );
19151930 CDiskTxPos pos (pindex->GetBlockPos (), GetSizeOfCompactSize (block.vtx .size ()));
19161931 std::vector<std::pair<uint256, CDiskTxPos> > vPos;
19171932 vPos.reserve (block.vtx .size ());
@@ -1922,7 +1937,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
19221937
19231938 nInputs += tx.vin .size ();
19241939 nSigOps += GetLegacySigOpCount (tx);
1925- if (nSigOps > MAX_BLOCK_SIGOPS )
1940+ if (nSigOps > nMaxLegacySigops )
19261941 return state.DoS (100 , error (" ConnectBlock(): too many sigops" ),
19271942 REJECT_INVALID , " bad-blk-sigops" );
19281943
@@ -1938,15 +1953,16 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
19381953 // this is to prevent a "rogue miner" from creating
19391954 // an incredibly-expensive-to-validate block.
19401955 nSigOps += GetP2SHSigOpCount (tx, view);
1941- if (nSigOps > MAX_BLOCK_SIGOPS )
1956+ if (nSigOps > nMaxLegacySigops )
19421957 return state.DoS (100 , error (" ConnectBlock(): too many sigops" ),
19431958 REJECT_INVALID , " bad-blk-sigops" );
19441959 }
19451960
19461961 nFees += view.GetValueIn (tx)-tx.GetValueOut ();
19471962
19481963 std::vector<CScriptCheck> vChecks;
1949- if (!CheckInputs (tx, state, view, fScriptChecks , flags, false , nScriptCheckThreads ? &vChecks : NULL ))
1964+ if (!CheckInputs (tx, state, view, fScriptChecks , flags, false ,
1965+ &costTracker, nScriptCheckThreads ? &vChecks : NULL ))
19501966 return false ;
19511967 control.Add (vChecks);
19521968 }
@@ -1972,6 +1988,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
19721988
19731989 if (!control.Wait ())
19741990 return state.DoS (100 , false );
1991+
19751992 int64_t nTime2 = GetTimeMicros (); nTimeVerify += nTime2 - nTimeStart;
19761993 LogPrint (" bench" , " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs]\n " , nInputs - 1 , 0.001 * (nTime2 - nTimeStart), nInputs <= 1 ? 0 : 0.001 * (nTime2 - nTimeStart) / (nInputs-1 ), nTimeVerify * 0.000001 );
19771994
@@ -2170,7 +2187,7 @@ void static UpdateTip(CBlockIndex *pindexNew) {
21702187 const CBlockIndex* pindex = chainActive.Tip ();
21712188 for (int i = 0 ; i < 100 && pindex != NULL ; i++)
21722189 {
2173- if (!Block ::VersionKnown (pindex->nVersion ))
2190+ if (!CBlock ::VersionKnown (pindex->nVersion ))
21742191 ++nUpgraded;
21752192 pindex = pindex->pprev ;
21762193 }
@@ -2805,7 +2822,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
28052822 {
28062823 nSigOps += GetLegacySigOpCount (tx);
28072824 }
2808- if (nSigOps > MAX_BLOCK_SIGOPS )
2825+ if (nSigOps > MaxLegacySigops (block. nTime ) )
28092826 return state.DoS (100 , error (" CheckBlock(): out-of-bounds SigOpCount" ),
28102827 REJECT_INVALID , " bad-blk-sigops" , true );
28112828
@@ -5270,6 +5287,29 @@ unsigned int MaxBlockSize(uint32_t nBlockTime)
52705287 return MAX_BLOCK_SIZE ;
52715288}
52725289
5290+ /* * Maximum size of a block */
5291+ unsigned int MaxBlockSigops (uint32_t nBlockTime)
5292+ {
5293+ if (nBlockTime < sizeForkTime.load ())
5294+ return std::numeric_limits<uint32_t >::max (); // Use old way of counting
5295+ return MAX_BLOCK_SIGOPS ;
5296+ }
5297+ /* * Maximum size of a block */
5298+ unsigned int MaxBlockSighash (uint32_t nBlockTime)
5299+ {
5300+ if (nBlockTime < sizeForkTime.load ())
5301+ return std::numeric_limits<uint32_t >::max (); // no limit before
5302+ return MAX_BLOCK_SIGHASH ;
5303+ }
5304+
5305+ /* * Maximum legacy (miscounted) sigops in a block */
5306+ uint32_t MaxLegacySigops (uint32_t nBlockTime)
5307+ {
5308+ if (nBlockTime < sizeForkTime.load ())
5309+ return MAX_BLOCK_SIGOPS ;
5310+ return std::numeric_limits<uint32_t >::max (); // Use accurately-counted limit
5311+ }
5312+
52735313uint32_t ForkBits (uint32_t nTime) {
52745314 uint32_t bits = 0 ;
52755315 AssertLockHeld (cs_main);
0 commit comments