Skip to content

Commit

Permalink
Reject non-final txs even in testnet/regtest
Browse files Browse the repository at this point in the history
Previous behavior with IsFinalTx() being an IsStandard() rule was rather
confusing and interferred with testing of protocols that depended on
nLockTime.
  • Loading branch information
petertodd committed Jan 4, 2015
1 parent f914f1a commit 0ea28ba
Showing 1 changed file with 20 additions and 23 deletions.
43 changes: 20 additions & 23 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -620,34 +620,11 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)

bool IsStandardTx(const CTransaction& tx, string& reason)
{
AssertLockHeld(cs_main);
if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) {
reason = "version";
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
// almost as much to process as they cost the sender in fees, because
// computing signature hashes is O(ninputs*txsize). Limiting transactions
Expand Down Expand Up @@ -936,6 +913,26 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
error("AcceptToMemoryPool : nonstandard transaction: %s", 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?
uint256 hash = tx.GetHash();
if (pool.exists(hash))
Expand Down

0 comments on commit 0ea28ba

Please sign in to comment.