Auto merge of #1017 - ebfull:coinbase-must-be-protected, r=ebfull
Enforce that coinbases must be protected This PR forces miners to place their funds in the private value transfer system, making "transparent coins" opt-in for users, and increasing privacy for all participants on a systemic level. Closes #101.
This commit is contained in:
59
src/main.cpp
59
src/main.cpp
@@ -62,6 +62,7 @@ bool fPruneMode = false;
|
||||
bool fIsBareMultisigStd = true;
|
||||
bool fCheckBlockIndex = false;
|
||||
bool fCheckpointsEnabled = true;
|
||||
bool fCoinbaseEnforcedProtectionEnabled = true;
|
||||
size_t nCoinCacheUsage = 5000 * 300;
|
||||
uint64_t nPruneTarget = 0;
|
||||
bool fAlerts = DEFAULT_ALERTS;
|
||||
@@ -1219,7 +1220,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
|
||||
// Check against previous transactions
|
||||
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
||||
if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true))
|
||||
if (!ContextualCheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus()))
|
||||
{
|
||||
return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString());
|
||||
}
|
||||
@@ -1233,7 +1234,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
|
||||
// There is a similar check in CreateNewBlock() to prevent creating
|
||||
// invalid blocks, however allowing such transactions into the mempool
|
||||
// can be exploited as a DoS attack.
|
||||
if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true))
|
||||
if (!ContextualCheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true, Params().GetConsensus()))
|
||||
{
|
||||
return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString());
|
||||
}
|
||||
@@ -1604,7 +1605,7 @@ bool CScriptCheck::operator()() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks)
|
||||
bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector<CScriptCheck> *pvChecks)
|
||||
{
|
||||
if (!tx.IsCoinBase())
|
||||
{
|
||||
@@ -1620,10 +1621,6 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
||||
if (!inputs.HavePourRequirements(tx))
|
||||
return state.Invalid(error("CheckInputs(): %s pour requirements not met", tx.GetHash().ToString()));
|
||||
|
||||
// While checking, GetBestBlock() refers to the parent block.
|
||||
// This is also true for mempool checks.
|
||||
CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
|
||||
int nSpendHeight = pindexPrev->nHeight + 1;
|
||||
CAmount nValueIn = 0;
|
||||
CAmount nFees = 0;
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
@@ -1632,12 +1629,16 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
||||
const CCoins *coins = inputs.AccessCoins(prevout.hash);
|
||||
assert(coins);
|
||||
|
||||
// If prev is coinbase, check that it's matured
|
||||
if (coins->IsCoinBase()) {
|
||||
if (nSpendHeight - coins->nHeight < COINBASE_MATURITY)
|
||||
// Ensure that coinbases cannot be spent to transparent outputs
|
||||
// Disabled on regtest
|
||||
if (fCoinbaseEnforcedProtectionEnabled &&
|
||||
consensusParams.fCoinbaseMustBeProtected &&
|
||||
!tx.vout.empty()) {
|
||||
return state.Invalid(
|
||||
error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight),
|
||||
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
|
||||
error("CheckInputs(): tried to spend coinbase with transparent outputs"),
|
||||
REJECT_INVALID, "bad-txns-coinbase-spend-has-transparent-outputs");
|
||||
}
|
||||
}
|
||||
|
||||
// Check for negative or overflow input values
|
||||
@@ -1715,6 +1716,40 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, const Consensus::Params& consensusParams, std::vector<CScriptCheck> *pvChecks)
|
||||
{
|
||||
if (!NonContextualCheckInputs(tx, state, inputs, fScriptChecks, flags, cacheStore, consensusParams, pvChecks)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tx.IsCoinBase())
|
||||
{
|
||||
// While checking, GetBestBlock() refers to the parent block.
|
||||
// This is also true for mempool checks.
|
||||
CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
|
||||
int nSpendHeight = pindexPrev->nHeight + 1;
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++)
|
||||
{
|
||||
const COutPoint &prevout = tx.vin[i].prevout;
|
||||
const CCoins *coins = inputs.AccessCoins(prevout.hash);
|
||||
// Assertion is okay because NonContextualCheckInputs ensures the inputs
|
||||
// are available.
|
||||
assert(coins);
|
||||
|
||||
// If prev is coinbase, check that it's matured
|
||||
if (coins->IsCoinBase()) {
|
||||
if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) {
|
||||
return state.Invalid(
|
||||
error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight),
|
||||
REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
|
||||
@@ -2106,7 +2141,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
|
||||
nFees += view.GetValueIn(tx)-tx.GetValueOut();
|
||||
|
||||
std::vector<CScriptCheck> vChecks;
|
||||
if (!CheckInputs(tx, state, view, fScriptChecks, flags, false, nScriptCheckThreads ? &vChecks : NULL))
|
||||
if (!ContextualCheckInputs(tx, state, view, fScriptChecks, flags, false, chainparams.GetConsensus(), nScriptCheckThreads ? &vChecks : NULL))
|
||||
return false;
|
||||
control.Add(vChecks);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user