|
|
|
@ -794,7 +794,25 @@ bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>* prevHeig
|
|
|
|
|
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(mempool.cs);
|
|
|
|
@ -810,25 +828,57 @@ bool CheckSequenceLocks(const CTransaction &tx, int flags)
|
|
|
|
|
// *next* block, we need to use one more than chainActive.Height()
|
|
|
|
|
index.nHeight = tip->nHeight + 1;
|
|
|
|
|
|
|
|
|
|
// pcoinsTip contains the UTXO set for chainActive.Tip()
|
|
|
|
|
CCoinsViewMemPool viewMemPool(pcoinsTip, mempool);
|
|
|
|
|
std::vector<int> prevheights;
|
|
|
|
|
prevheights.resize(tx.vin.size());
|
|
|
|
|
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
|
|
|
|
|
const CTxIn& txin = tx.vin[txinIndex];
|
|
|
|
|
CCoins coins;
|
|
|
|
|
if (!viewMemPool.GetCoins(txin.prevout.hash, coins)) {
|
|
|
|
|
return error("%s: Missing input", __func__);
|
|
|
|
|
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()
|
|
|
|
|
CCoinsViewMemPool viewMemPool(pcoinsTip, mempool);
|
|
|
|
|
std::vector<int> prevheights;
|
|
|
|
|
prevheights.resize(tx.vin.size());
|
|
|
|
|
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) {
|
|
|
|
|
const CTxIn& txin = tx.vin[txinIndex];
|
|
|
|
|
CCoins coins;
|
|
|
|
|
if (!viewMemPool.GetCoins(txin.prevout.hash, coins)) {
|
|
|
|
|
return error("%s: Missing input", __func__);
|
|
|
|
|
}
|
|
|
|
|
if (coins.nHeight == MEMPOOL_HEIGHT) {
|
|
|
|
|
// Assume all mempool transaction confirm in the next block
|
|
|
|
|
prevheights[txinIndex] = tip->nHeight + 1;
|
|
|
|
|
} else {
|
|
|
|
|
prevheights[txinIndex] = coins.nHeight;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (coins.nHeight == MEMPOOL_HEIGHT) {
|
|
|
|
|
// Assume all mempool transaction confirm in the next block
|
|
|
|
|
prevheights[txinIndex] = tip->nHeight + 1;
|
|
|
|
|
} else {
|
|
|
|
|
prevheights[txinIndex] = coins.nHeight;
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::pair<int, int64_t> lockPair = CalculateSequenceLocks(tx, flags, &prevheights, index);
|
|
|
|
|
return EvaluateSequenceLocks(index, lockPair);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1017,6 +1067,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
|
|
|
|
CCoinsViewCache view(&dummy);
|
|
|
|
|
|
|
|
|
|
CAmount nValueIn = 0;
|
|
|
|
|
LockPoints lp;
|
|
|
|
|
{
|
|
|
|
|
LOCK(pool.cs);
|
|
|
|
|
CCoinsViewMemPool viewMemPool(pcoinsTip, pool);
|
|
|
|
@ -1060,7 +1111,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
|
|
|
|
|
// be mined yet.
|
|
|
|
|
// Must keep pool.cs for this unless we change CheckSequenceLocks to take a
|
|
|
|
|
// 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");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -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();
|
|
|
|
|
|
|
|
|
|
// Check that the transaction doesn't have an excessive number of
|
|
|
|
|