mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-19 14:53:43 +01:00
Merge #7187: Keep reorgs fast for SequenceLocks checks
982670c Add LockPoints (Alex Morcos)
This commit is contained in:
89
src/main.cpp
89
src/main.cpp
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user