|
|
@ -794,7 +794,25 @@ bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeig |
|
|
|
return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block)); |
|
|
|
return EvaluateSequenceLocks(block, CalculateSequenceLocks(tx, flags, prevHeights, block)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool CheckSequenceLocks(const CTransaction &tx, int flags) |
|
|
|
bool TestLockPointValidity(const LockPoints* lp) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
AssertLockHeld(cs_main); |
|
|
|
|
|
|
|
assert(lp); |
|
|
|
|
|
|
|
// If there are relative lock times then the maxInputBlock will be set
|
|
|
|
|
|
|
|
// If there are no relative lock times, the LockPoints don't depend on the chain
|
|
|
|
|
|
|
|
if (lp->maxInputBlock) { |
|
|
|
|
|
|
|
// Check whether chainActive is an extension of the block at which the LockPoints
|
|
|
|
|
|
|
|
// calculation was valid. If not LockPoints are no longer valid
|
|
|
|
|
|
|
|
if (!chainActive.Contains(lp->maxInputBlock)) { |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// LockPoints still valid
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool CheckSequenceLocks(const CTransaction &tx, int flags, LockPoints* lp, bool useExistingLockPoints) |
|
|
|
{ |
|
|
|
{ |
|
|
|
AssertLockHeld(cs_main); |
|
|
|
AssertLockHeld(cs_main); |
|
|
|
AssertLockHeld(mempool.cs); |
|
|
|
AssertLockHeld(mempool.cs); |
|
|
@ -810,6 +828,13 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags) |
|
|
|
// *next* block, we need to use one more than chainActive.Height()
|
|
|
|
// *next* block, we need to use one more than chainActive.Height()
|
|
|
|
index.nHeight = tip->nHeight + 1; |
|
|
|
index.nHeight = tip->nHeight + 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::pair<int, int64_t> lockPair; |
|
|
|
|
|
|
|
if (useExistingLockPoints) { |
|
|
|
|
|
|
|
assert(lp); |
|
|
|
|
|
|
|
lockPair.first = lp->height; |
|
|
|
|
|
|
|
lockPair.second = lp->time; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
// pcoinsTip contains the UTXO set for chainActive.Tip()
|
|
|
|
// pcoinsTip contains the UTXO set for chainActive.Tip()
|
|
|
|
CCoinsViewMemPool viewMemPool(pcoinsTip, mempool); |
|
|
|
CCoinsViewMemPool viewMemPool(pcoinsTip, mempool); |
|
|
|
std::vector<int> prevheights; |
|
|
|
std::vector<int> prevheights; |
|
|
@ -827,8 +852,33 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags) |
|
|
|
prevheights[txinIndex] = coins.nHeight; |
|
|
|
prevheights[txinIndex] = coins.nHeight; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
lockPair = CalculateSequenceLocks(tx, flags, &prevheights, index); |
|
|
|
std::pair<int, int64_t> lockPair = CalculateSequenceLocks(tx, flags, &prevheights, index); |
|
|
|
if (lp) { |
|
|
|
|
|
|
|
lp->height = lockPair.first; |
|
|
|
|
|
|
|
lp->time = lockPair.second; |
|
|
|
|
|
|
|
// Also store the hash of the block with the highest height of
|
|
|
|
|
|
|
|
// all the blocks which have sequence locked prevouts.
|
|
|
|
|
|
|
|
// This hash needs to still be on the chain
|
|
|
|
|
|
|
|
// for these LockPoint calculations to be valid
|
|
|
|
|
|
|
|
// Note: It is impossible to correctly calculate a maxInputBlock
|
|
|
|
|
|
|
|
// if any of the sequence locked inputs depend on unconfirmed txs,
|
|
|
|
|
|
|
|
// except in the special case where the relative lock time/height
|
|
|
|
|
|
|
|
// is 0, which is equivalent to no sequence lock. Since we assume
|
|
|
|
|
|
|
|
// input height of tip+1 for mempool txs and test the resulting
|
|
|
|
|
|
|
|
// lockPair from CalculateSequenceLocks against tip+1. We know
|
|
|
|
|
|
|
|
// EvaluateSequenceLocks will fail if there was a non-zero sequence
|
|
|
|
|
|
|
|
// lock on a mempool input, so we can use the return value of
|
|
|
|
|
|
|
|
// CheckSequenceLocks to indicate the LockPoints validity
|
|
|
|
|
|
|
|
int maxInputHeight = 0; |
|
|
|
|
|
|
|
BOOST_FOREACH(int height, prevheights) { |
|
|
|
|
|
|
|
// Can ignore mempool inputs since we'll fail if they had non-zero locks
|
|
|
|
|
|
|
|
if (height != tip->nHeight+1) { |
|
|
|
|
|
|
|
maxInputHeight = std::max(maxInputHeight, height); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
lp->maxInputBlock = tip->GetAncestor(maxInputHeight); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
return EvaluateSequenceLocks(index, lockPair); |
|
|
|
return EvaluateSequenceLocks(index, lockPair); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1017,6 +1067,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C |
|
|
|
CCoinsViewCache view(&dummy); |
|
|
|
CCoinsViewCache view(&dummy); |
|
|
|
|
|
|
|
|
|
|
|
CAmount nValueIn = 0; |
|
|
|
CAmount nValueIn = 0; |
|
|
|
|
|
|
|
LockPoints lp; |
|
|
|
{ |
|
|
|
{ |
|
|
|
LOCK(pool.cs); |
|
|
|
LOCK(pool.cs); |
|
|
|
CCoinsViewMemPool viewMemPool(pcoinsTip, pool); |
|
|
|
CCoinsViewMemPool viewMemPool(pcoinsTip, pool); |
|
|
@ -1060,7 +1111,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C |
|
|
|
// be mined yet.
|
|
|
|
// be mined yet.
|
|
|
|
// Must keep pool.cs for this unless we change CheckSequenceLocks to take a
|
|
|
|
// Must keep pool.cs for this unless we change CheckSequenceLocks to take a
|
|
|
|
// CoinsViewCache instead of create its own
|
|
|
|
// CoinsViewCache instead of create its own
|
|
|
|
if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS)) |
|
|
|
if (!CheckSequenceLocks(tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) |
|
|
|
return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final"); |
|
|
|
return state.DoS(0, false, REJECT_NONSTANDARD, "non-BIP68-final"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1092,7 +1143,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps); |
|
|
|
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps, lp); |
|
|
|
unsigned int nSize = entry.GetTxSize(); |
|
|
|
unsigned int nSize = entry.GetTxSize(); |
|
|
|
|
|
|
|
|
|
|
|
// Check that the transaction doesn't have an excessive number of
|
|
|
|
// Check that the transaction doesn't have an excessive number of
|
|
|
|