From ff5e9cd74dba04880427c397d6b3d58dad8316c0 Mon Sep 17 00:00:00 2001 From: Gregory Sanders Date: Fri, 15 Sep 2017 14:47:57 -0400 Subject: [PATCH] mempool and policy support for peg-in inputs --- src/policy/policy.cpp | 6 +++++- src/txmempool.cpp | 3 ++- src/validation.cpp | 28 ++++++++++++++++++++++++++-- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index ce3f037666..2d0299a62d 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -120,6 +120,10 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) for (unsigned int i = 0; i < tx.vin.size(); i++) { + if (tx.vin[i].m_is_pegin) { + // This deals with p2sh in general only + continue; + } const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]); // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed @@ -169,7 +173,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) if (tx.wit.vtxinwit.size() <= i || tx.wit.vtxinwit[i].scriptWitness.IsNull()) continue; - const CTxOut &prev = mapInputs.GetOutputFor(tx.vin[i]); + const CTxOut &prev = tx.vin[i].m_is_pegin ? GetPeginOutputFromWitness(tx.wit.vtxinwit[i].m_pegin_witness) : mapInputs.GetOutputFor(tx.vin[i]); // get the scriptPubKey corresponding to this input: CScript prevScript = prev.scriptPubKey; diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 722d89764b..6610015ba0 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -709,8 +709,9 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const parentSigOpCost += it2->GetSigOpCost(); } } else { + // peg-in inputs are not sanity-checked to be valid const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash); - assert(coins && coins->IsAvailable(txin.prevout.n)); + assert(txin.m_is_pegin || (coins && coins->IsAvailable(txin.prevout.n))); } // Check whether its inputs are marked in mapNextTx. auto it3 = mapNextTx.find(txin.prevout); diff --git a/src/validation.cpp b/src/validation.cpp index 4b03dd31a4..7e4c12501c 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1124,6 +1124,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C // Note that this does not check for the presence of actual outputs (see the next check for that), // and only helps with filling in pfMissingInputs (to determine missing vs spent). BOOST_FOREACH(const CTxIn txin, tx.vin) { + // Don't look for coins that only exist in parent chain + if (txin.m_is_pegin) { + continue; + } if (!pcoinsTip->HaveCoinsInCache(txin.prevout.hash)) vHashTxnToUncache.push_back(txin.prevout.hash); if (!view.HaveCoins(txin.prevout.hash)) { @@ -1137,6 +1141,22 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C if (!view.HaveInputs(tx)) return state.Invalid(false, REJECT_DUPLICATE, "bad-txns-inputs-spent"); + // Extract peg-in inputs, pass set to mempool entry. Validity of pegins checked in CheckInputs + for (unsigned int i = 0; i < tx.vin.size(); i++) { + if (tx.vin[i].m_is_pegin) { + // Quick check of pegin witness and prevout to extract db entry + if (tx.wit.vtxinwit.size() <= i || tx.wit.vtxinwit[i].m_pegin_witness.stack.size() < 6 || uint256(tx.wit.vtxinwit[i].m_pegin_witness.stack[2]).IsNull() || tx.vin[i].prevout.hash.IsNull()) { + return state.Invalid(false, REJECT_INVALID, "pegin-no-witness"); + } + std::pair pegin = std::make_pair(uint256(tx.wit.vtxinwit[i].m_pegin_witness.stack[2]), tx.vin[i].prevout); + // This assumes non-null prevout and genesis block hash + if (view.IsWithdrawSpent(pegin)) { + return state.Invalid(false, REJECT_CONFLICT, "pegin-already-claimed"); + } + setPeginsSpent.insert(pegin); + } + } + // Bring the best block into scope view.GetBestBlock(); @@ -1171,14 +1191,18 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C double nPriorityDummy = 0; pool.ApplyDeltas(hash, nPriorityDummy, nModifiedFees); - CAmount inChainInputValue; - double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue); + // Neuter priority in mempool + CAmount inChainInputValue = 0; + double dPriority = 0; // Keep track of transactions that spend a coinbase, which we re-scan // during reorgs to ensure COINBASE_MATURITY is still met. // Also track withdraw lock spends to allow them through free relay bool fSpendsCoinbase = false; BOOST_FOREACH(const CTxIn &txin, tx.vin) { + if (txin.m_is_pegin) { + continue; + } const CCoins *coins = view.AccessCoins(txin.prevout.hash); if (coins->IsCoinBase()) { fSpendsCoinbase = true;