|
|
@ -625,34 +625,11 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) |
|
|
|
|
|
|
|
|
|
|
|
bool IsStandardTx(const CTransaction& tx, string& reason) |
|
|
|
bool IsStandardTx(const CTransaction& tx, string& reason) |
|
|
|
{ |
|
|
|
{ |
|
|
|
AssertLockHeld(cs_main); |
|
|
|
|
|
|
|
if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) { |
|
|
|
if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) { |
|
|
|
reason = "version"; |
|
|
|
reason = "version"; |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Treat non-final transactions as non-standard to prevent a specific type
|
|
|
|
|
|
|
|
// of double-spend attack, as well as DoS attacks. (if the transaction
|
|
|
|
|
|
|
|
// can't be mined, the attacker isn't expending resources broadcasting it)
|
|
|
|
|
|
|
|
// Basically we don't want to propagate transactions that can't be included in
|
|
|
|
|
|
|
|
// the next block.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// However, IsFinalTx() is confusing... Without arguments, it uses
|
|
|
|
|
|
|
|
// chainActive.Height() to evaluate nLockTime; when a block is accepted, chainActive.Height()
|
|
|
|
|
|
|
|
// is set to the value of nHeight in the block. However, when IsFinalTx()
|
|
|
|
|
|
|
|
// is called within CBlock::AcceptBlock(), the height of the block *being*
|
|
|
|
|
|
|
|
// evaluated is what is used. Thus if we want to know if a transaction can
|
|
|
|
|
|
|
|
// be part of the *next* block, we need to call IsFinalTx() with one more
|
|
|
|
|
|
|
|
// than chainActive.Height().
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// Timestamps on the other hand don't get any special treatment, because we
|
|
|
|
|
|
|
|
// can't know what timestamp the next block will have, and there aren't
|
|
|
|
|
|
|
|
// timestamp applications where it matters.
|
|
|
|
|
|
|
|
if (!IsFinalTx(tx, chainActive.Height() + 1)) { |
|
|
|
|
|
|
|
reason = "non-final"; |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Extremely large transactions with lots of inputs can cost the network
|
|
|
|
// Extremely large transactions with lots of inputs can cost the network
|
|
|
|
// almost as much to process as they cost the sender in fees, because
|
|
|
|
// almost as much to process as they cost the sender in fees, because
|
|
|
|
// computing signature hashes is O(ninputs*txsize). Limiting transactions
|
|
|
|
// computing signature hashes is O(ninputs*txsize). Limiting transactions
|
|
|
@ -941,6 +918,26 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa |
|
|
|
error("AcceptToMemoryPool : nonstandard transaction: %s", reason), |
|
|
|
error("AcceptToMemoryPool : nonstandard transaction: %s", reason), |
|
|
|
REJECT_NONSTANDARD, reason); |
|
|
|
REJECT_NONSTANDARD, reason); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Only accept nLockTime-using transactions that can be mined in the next
|
|
|
|
|
|
|
|
// block; we don't want our mempool filled up with transactions that can't
|
|
|
|
|
|
|
|
// be mined yet.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// However, IsFinalTx() is confusing... Without arguments, it uses
|
|
|
|
|
|
|
|
// chainActive.Height() to evaluate nLockTime; when a block is accepted,
|
|
|
|
|
|
|
|
// chainActive.Height() is set to the value of nHeight in the block.
|
|
|
|
|
|
|
|
// However, when IsFinalTx() is called within CBlock::AcceptBlock(), the
|
|
|
|
|
|
|
|
// height of the block *being* evaluated is what is used. Thus if we want
|
|
|
|
|
|
|
|
// to know if a transaction can be part of the *next* block, we need to
|
|
|
|
|
|
|
|
// call IsFinalTx() with one more than chainActive.Height().
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// Timestamps on the other hand don't get any special treatment, because we
|
|
|
|
|
|
|
|
// can't know what timestamp the next block will have, and there aren't
|
|
|
|
|
|
|
|
// timestamp applications where it matters.
|
|
|
|
|
|
|
|
if (!IsFinalTx(tx, chainActive.Height() + 1)) |
|
|
|
|
|
|
|
return state.DoS(0, |
|
|
|
|
|
|
|
error("AcceptToMemoryPool : non-final"), |
|
|
|
|
|
|
|
REJECT_NONSTANDARD, "non-final"); |
|
|
|
|
|
|
|
|
|
|
|
// is it already in the memory pool?
|
|
|
|
// is it already in the memory pool?
|
|
|
|
uint256 hash = tx.GetHash(); |
|
|
|
uint256 hash = tx.GetHash(); |
|
|
|
if (pool.exists(hash)) |
|
|
|
if (pool.exists(hash)) |
|
|
|