@ -684,8 +684,8 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c
@@ -684,8 +684,8 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(c
// have been mined or received.
// 100 orphans, each of which is at most 99,999 bytes big is
// at most 10 megabytes of orphans and somewhat more byprev index (in the worst case):
unsigned int sz = tx . GetSerializeSize ( SER_NETWORK , CTransaction : : CURRENT_VERSION ) ;
if ( sz > = MAX_STANDARD_TX_SIZE )
unsigned int sz = GetTransactionCost ( tx ) ;
if ( sz > = MAX_STANDARD_TX_COST )
{
LogPrint ( " mempool " , " ignoring large orphan tx (size: %u, hash: %s) \n " , sz , hash . ToString ( ) ) ;
return false ;
@ -1018,8 +1018,24 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
@@ -1018,8 +1018,24 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
return nSigOps ;
}
int64_t GetTransactionSigOpCost ( const CTransaction & tx , const CCoinsViewCache & inputs , int flags )
{
int64_t nSigOps = GetLegacySigOpCount ( tx ) * WITNESS_SCALE_FACTOR ;
if ( tx . IsCoinBase ( ) )
return nSigOps ;
if ( flags & SCRIPT_VERIFY_P2SH ) {
nSigOps + = GetP2SHSigOpCount ( tx , inputs ) * WITNESS_SCALE_FACTOR ;
}
for ( unsigned int i = 0 ; i < tx . vin . size ( ) ; i + + )
{
const CTxOut & prevout = inputs . GetOutputFor ( tx . vin [ i ] ) ;
nSigOps + = CountWitnessSigOps ( tx . vin [ i ] . scriptSig , prevout . scriptPubKey , i < tx . wit . vtxinwit . size ( ) ? & tx . wit . vtxinwit [ i ] . scriptWitness : NULL , flags ) ;
}
return nSigOps ;
}
@ -1033,7 +1049,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
@@ -1033,7 +1049,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
if ( tx . vout . empty ( ) )
return state . DoS ( 10 , false , REJECT_INVALID , " bad-txns-vout-empty " ) ;
// Size limits (this doesn't take the witness into account, as that hasn't been checked for malleability)
if ( : : GetSerializeSize ( tx , SER_NETWORK , PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS ) > MAX_BLOCK_SIZE )
if ( : : GetSerializeSize ( tx , SER_NETWORK , PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS ) > MAX_BLOCK_BASE_ SIZE )
return state . DoS ( 100 , false , REJECT_INVALID , " bad-txns-oversize " ) ;
// Check for negative or overflow output values
@ -1239,8 +1255,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
@@ -1239,8 +1255,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
if ( fRequireStandard & & ! AreInputsStandard ( tx , view ) )
return state . Invalid ( false , REJECT_NONSTANDARD , " bad-txns-nonstandard-inputs " ) ;
unsigned int nSigOps = GetLegacySigOpCount ( tx ) ;
nSigOps + = GetP2SHSigOpCount ( tx , view ) ;
int64_t nSigOpsCost = GetTransactionSigOpCost ( tx , view , STANDARD_SCRIPT_VERIFY_FLAGS ) ;
CAmount nValueOut = tx . GetValueOut ( ) ;
CAmount nFees = nValueIn - nValueOut ;
@ -1263,7 +1278,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
@@ -1263,7 +1278,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
}
}
CTxMemPoolEntry entry ( tx , nFees , GetTime ( ) , dPriority , chainActive . Height ( ) , pool . HasNoInputsOf ( tx ) , inChainInputValue , fSpendsCoinbase , nSigOps , lp ) ;
CTxMemPoolEntry entry ( tx , nFees , GetTime ( ) , dPriority , chainActive . Height ( ) , pool . HasNoInputsOf ( tx ) , inChainInputValue , fSpendsCoinbase , nSigOpsCost , lp ) ;
unsigned int nSize = entry . GetTxSize ( ) ;
// Check that the transaction doesn't have an excessive number of
@ -1271,9 +1286,9 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
@@ -1271,9 +1286,9 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
// itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than
// MAX_BLOCK_SIGOPS; we still consider this an invalid rather than
// merely non-standard transaction.
if ( ( nSigOps > MAX_STANDARD_TX_SIGOPS ) | | ( nBytesPerSigOp & & nSigOps > nSize / nBytesPerSigOp ) )
if ( ( nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST ) | | ( nBytesPerSigOp & & nSigOpsCost > nSize * WITNESS_SCALE_FACTOR / nBytesPerSigOp ) )
return state . DoS ( 0 , false , REJECT_NONSTANDARD , " bad-txns-too-many-sigops " , false ,
strprintf ( " %d " , nSigOps ) ) ;
strprintf ( " %d " , nSigOpsCost ) ) ;
CAmount mempoolRejectFee = pool . GetMinFee ( GetArg ( " -maxmempool " , DEFAULT_MAX_MEMPOOL_SIZE ) * 1000000 ) . GetFee ( nSize ) ;
if ( mempoolRejectFee > 0 & & nModifiedFees < mempoolRejectFee ) {
@ -2439,7 +2454,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
@@ -2439,7 +2454,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
std : : vector < int > prevheights ;
CAmount nFees = 0 ;
int nInputs = 0 ;
unsigned int nSigOps = 0 ;
int64_t nSigOpsCost = 0 ;
CDiskTxPos pos ( pindex - > GetBlockPos ( ) , GetSizeOfCompactSize ( block . vtx . size ( ) ) ) ;
std : : vector < std : : pair < uint256 , CDiskTxPos > > vPos ;
vPos . reserve ( block . vtx . size ( ) ) ;
@ -2449,10 +2464,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
@@ -2449,10 +2464,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
const CTransaction & tx = block . vtx [ i ] ;
nInputs + = tx . vin . size ( ) ;
nSigOps + = GetLegacySigOpCount ( tx ) ;
if ( nSigOps > MAX_BLOCK_SIGOPS )
return state . DoS ( 100 , error ( " ConnectBlock(): too many sigops " ) ,
REJECT_INVALID , " bad-blk-sigops " ) ;
if ( ! tx . IsCoinBase ( ) )
{
@ -2483,18 +2494,19 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
@@ -2483,18 +2494,19 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return state . DoS ( 100 , error ( " %s: contains a non-BIP68-final transaction " , __func__ ) ,
REJECT_INVALID , " bad-txns-nonfinal " ) ;
}
}
if ( fStrictPayToScriptHash )
{
// Add in sigops done by pay-to-script-hash inputs;
// this is to prevent a "rogue miner" from creating
// an incredibly-expensive-to-validate block.
nSigOps + = GetP2SHSigOpCount ( tx , view ) ;
if ( nSigOps > MAX_BLOCK_SIGOPS )
// GetTransactionSigOpCost counts 3 types of sigops:
// * legacy (always)
// * p2sh (when P2SH enabled in flags and excludes coinbase)
// * witness (when witness enabled in flags and excludes coinbase)
nSigOpsCost + = GetTransactionSigOpCost ( tx , view , flags ) ;
if ( nSigOpsCost > MAX_BLOCK_SIGOPS_COST )
return state . DoS ( 100 , error ( " ConnectBlock(): too many sigops " ) ,
REJECT_INVALID , " bad-blk-sigops " ) ;
}
if ( ! tx . IsCoinBase ( ) )
{
nFees + = view . GetValueIn ( tx ) - tx . GetValueOut ( ) ;
std : : vector < CScriptCheck > vChecks ;
@ -3417,9 +3429,11 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
@@ -3417,9 +3429,11 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
// All potential-corruption validation must be done before we do any
// transaction validation, as otherwise we may mark the header as invalid
// because we receive the wrong transactions for it.
// Note that witness malleability is checked in ContextualCheckBlock, so no
// checks that use witness data may be performed here.
// Size limits
if ( block . vtx . empty ( ) | | block . vtx . size ( ) > MAX_BLOCK_SIZE | | : : GetSerializeSize ( block , SER_NETWORK , PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS ) > MAX_BLOCK_SIZE )
if ( block . vtx . empty ( ) | | block . vtx . size ( ) > MAX_BLOCK_BASE_ SIZE | | : : GetSerializeSize ( block , SER_NETWORK , PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS ) > MAX_BLOCK_BASE _SIZE )
return state . DoS ( 100 , false , REJECT_INVALID , " bad-blk-length " , false , " size limits failed " ) ;
// First transaction must be coinbase, the rest must not be
@ -3440,7 +3454,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
@@ -3440,7 +3454,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
{
nSigOps + = GetLegacySigOpCount ( tx ) ;
}
if ( nSigOps > MAX_BLOCK_SIGOPS )
if ( nSigOps * WITNESS_SCALE_FACTOR > MAX_BLOCK_SIGOPS_COST )
return state . DoS ( 100 , false , REJECT_INVALID , " bad-blk-sigops " , false , " out-of-bounds SigOpCount " ) ;
if ( fCheckPOW & & fCheckMerkleRoot )
@ -3621,6 +3635,16 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
@@ -3621,6 +3635,16 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
}
}
// After the coinbase witness nonce and commitment are verified,
// we can check if the block cost passes (before we've checked the
// coinbase witness, it would be possible for the cost to be too
// large by filling up the coinbase witness, which doesn't change
// the block hash, so we couldn't mark the block as permanently
// failed).
if ( GetBlockCost ( block ) > MAX_BLOCK_COST ) {
return state . DoS ( 100 , error ( " ContextualCheckBlock(): cost limit failed " ) , REJECT_INVALID , " bad-blk-cost " ) ;
}
return true ;
}
@ -4284,7 +4308,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
@@ -4284,7 +4308,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
int nLoaded = 0 ;
try {
// This takes over fileIn and calls fclose() on it in the CBufferedFile destructor
CBufferedFile blkdat ( fileIn , 2 * MAX_BLOCK_SIZE , MAX_BLOCK_SIZE + 8 , SER_DISK , CLIENT_VERSION ) ;
CBufferedFile blkdat ( fileIn , 2 * MAX_BLOCK_SERIALIZED_S IZE , MAX_BLOCK_SERIALIZED _SIZE + 8 , SER_DISK , CLIENT_VERSION ) ;
uint64_t nRewind = blkdat . GetPos ( ) ;
while ( ! blkdat . eof ( ) ) {
boost : : this_thread : : interruption_point ( ) ;
@ -4303,7 +4327,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
@@ -4303,7 +4327,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
continue ;
// read size
blkdat > > nSize ;
if ( nSize < 80 | | nSize > MAX_BLOCK_SIZE )
if ( nSize < 80 | | nSize > MAX_BLOCK_SERIALIZED_S IZE )
continue ;
} catch ( const std : : exception & ) {
// no valid block header found; don't complain