|
|
|
@ -671,14 +671,8 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
@@ -671,14 +671,8 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
|
|
|
|
|
|
|
|
|
|
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) |
|
|
|
|
{ |
|
|
|
|
AssertLockHeld(cs_main); |
|
|
|
|
// Time based nLockTime implemented in 0.1.6
|
|
|
|
|
if (tx.nLockTime == 0) |
|
|
|
|
return true; |
|
|
|
|
if (nBlockHeight == 0) |
|
|
|
|
nBlockHeight = chainActive.Height(); |
|
|
|
|
if (nBlockTime == 0) |
|
|
|
|
nBlockTime = GetAdjustedTime(); |
|
|
|
|
if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime)) |
|
|
|
|
return true; |
|
|
|
|
BOOST_FOREACH(const CTxIn& txin, tx.vin) |
|
|
|
@ -687,6 +681,12 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
@@ -687,6 +681,12 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool CheckFinalTx(const CTransaction &tx) |
|
|
|
|
{ |
|
|
|
|
AssertLockHeld(cs_main); |
|
|
|
|
return IsFinalTx(tx, chainActive.Height() + 1, GetAdjustedTime()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check transaction inputs to mitigate two |
|
|
|
|
* potential denial-of-service attacks: |
|
|
|
@ -903,21 +903,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
@@ -903,21 +903,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
|
|
|
|
// 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"), |
|
|
|
|
if (!CheckFinalTx(tx)) |
|
|
|
|
return state.DoS(0, error("AcceptToMemoryPool: non-final"), |
|
|
|
|
REJECT_NONSTANDARD, "non-final"); |
|
|
|
|
|
|
|
|
|
// is it already in the memory pool?
|
|
|
|
|