aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/init.cpp21
-rw-r--r--src/main.cpp72
-rw-r--r--src/main.h7
-rw-r--r--src/wallet/rpcdump.cpp9
4 files changed, 75 insertions, 34 deletions
diff --git a/src/init.cpp b/src/init.cpp
index 4473cd9ec9..07f623d53c 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -715,16 +715,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS;
// if using block pruning, then disable txindex
- // also disable the wallet (for now, until SPV support is implemented in wallet)
if (GetArg("-prune", 0)) {
if (GetBoolArg("-txindex", false))
return InitError(_("Prune mode is incompatible with -txindex."));
#ifdef ENABLE_WALLET
- if (!GetBoolArg("-disablewallet", false)) {
- if (SoftSetBoolArg("-disablewallet", true))
- LogPrintf("%s : parameter interaction: -prune -> setting -disablewallet=1\n", __func__);
- else
- return InitError(_("Can't run with a wallet in prune mode."));
+ if (GetBoolArg("-rescan", false)) {
+ return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
}
#endif
}
@@ -1311,6 +1307,19 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
{
+ //We can't rescan beyond non-pruned blocks, stop and throw an error
+ //this might happen if a user uses a old wallet within a pruned node
+ // or if he ran -disablewallet for a longer time, then decided to re-enable
+ if (fPruneMode)
+ {
+ CBlockIndex *block = chainActive.Tip();
+ while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block)
+ block = block->pprev;
+
+ if (pindexRescan != block)
+ return InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"));
+ }
+
uiInterface.InitMessage(_("Rescanning..."));
LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
nStart = GetTimeMillis();
diff --git a/src/main.cpp b/src/main.cpp
index e92f64413a..cc9d277907 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1395,22 +1395,21 @@ 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)
+int GetSpendHeight(const CCoinsViewCache& inputs)
{
- if (!tx.IsCoinBase())
- {
- if (pvChecks)
- pvChecks->reserve(tx.vin.size());
+ LOCK(cs_main);
+ CBlockIndex* pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
+ return pindexPrev->nHeight + 1;
+}
+namespace Consensus {
+bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight)
+{
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
// for an attacker to attempt to split the network.
if (!inputs.HaveInputs(tx))
return state.Invalid(error("CheckInputs(): %s inputs unavailable", 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++)
@@ -1449,6 +1448,19 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
if (!MoneyRange(nFees))
return state.DoS(100, error("CheckInputs(): nFees out of range"),
REJECT_INVALID, "bad-txns-fee-outofrange");
+ return true;
+}
+}// namespace Consensus
+
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks)
+{
+ if (!tx.IsCoinBase())
+ {
+ if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs)))
+ return false;
+
+ if (pvChecks)
+ pvChecks->reserve(tx.vin.size());
// The first loop above does all the inexpensive checks.
// Only if ALL inputs pass do we perform expensive ECDSA signature checks.
@@ -2719,18 +2731,23 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
return true;
}
-bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev)
+static bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidationState& state, const CChainParams& chainparams, const uint256& hash)
{
- const CChainParams& chainParams = Params();
- const Consensus::Params& consensusParams = chainParams.GetConsensus();
- uint256 hash = block.GetHash();
- if (hash == consensusParams.hashGenesisBlock)
+ if (*pindexPrev->phashBlock == chainparams.GetConsensus().hashGenesisBlock)
return true;
- assert(pindexPrev);
-
int nHeight = pindexPrev->nHeight+1;
+ // Don't accept any forks from the main chain prior to last checkpoint
+ CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints());
+ if (pcheckpoint && nHeight < pcheckpoint->nHeight)
+ return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight));
+
+ return true;
+}
+bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev)
+{
+ const Consensus::Params& consensusParams = Params().GetConsensus();
// Check proof of work
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
return state.DoS(100, error("%s: incorrect proof of work", __func__),
@@ -2741,14 +2758,6 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
return state.Invalid(error("%s: block's timestamp is too early", __func__),
REJECT_INVALID, "time-too-old");
- if (fCheckpointsEnabled)
- {
- // Don't accept any forks from the main chain prior to last checkpoint
- CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainParams.Checkpoints());
- if (pcheckpoint && nHeight < pcheckpoint->nHeight)
- return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight));
- }
-
// Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
if (block.nVersion < 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams))
return state.Invalid(error("%s: rejected nVersion=1 block", __func__),
@@ -2818,6 +2827,9 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
if (pindexPrev->nStatus & BLOCK_FAILED_MASK)
return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
}
+ assert(pindexPrev);
+ if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, hash))
+ return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str());
if (!ContextualCheckBlockHeader(block, state, pindexPrev))
return false;
@@ -2933,8 +2945,11 @@ bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool
bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex * const pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot)
{
+ const CChainParams& chainparams = Params();
AssertLockHeld(cs_main);
- assert(pindexPrev == chainActive.Tip());
+ assert(pindexPrev && pindexPrev == chainActive.Tip());
+ if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, block.GetHash()))
+ return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str());
CCoinsViewCache viewNew(pcoinsTip);
CBlockIndex indexDummy(block);
@@ -4322,7 +4337,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
mempool.check(pcoinsTip);
RelayTransaction(tx);
vWorkQueue.push_back(inv.hash);
- vEraseQueue.push_back(inv.hash);
LogPrint("mempool", "AcceptToMemoryPool: peer=%d %s: accepted %s (poolsz %u)\n",
pfrom->id, pfrom->cleanSubVer,
@@ -4349,7 +4363,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// anyone relaying LegitTxX banned)
CValidationState stateDummy;
- vEraseQueue.push_back(orphanHash);
if (setMisbehaving.count(fromPeer))
continue;
@@ -4358,6 +4371,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
RelayTransaction(orphanTx);
vWorkQueue.push_back(orphanHash);
+ vEraseQueue.push_back(orphanHash);
}
else if (!fMissingInputs2)
{
@@ -4369,8 +4383,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
setMisbehaving.insert(fromPeer);
LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString());
}
- // too-little-fee orphan
+ // Has inputs but not accepted to mempool
+ // Probably non-standard or insufficient fee/priority
LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString());
+ vEraseQueue.push_back(orphanHash);
}
mempool.check(pcoinsTip);
}
diff --git a/src/main.h b/src/main.h
index abaedae207..7eaf58d716 100644
--- a/src/main.h
+++ b/src/main.h
@@ -487,4 +487,11 @@ extern CCoinsViewCache *pcoinsTip;
/** Global variable that points to the active block tree (protected by cs_main) */
extern CBlockTreeDB *pblocktree;
+/**
+ * Return the spend height, which is one more than the inputs.GetBestBlock().
+ * While checking, GetBestBlock() refers to the parent block. (protected by cs_main)
+ * This is also true for mempool checks.
+ */
+int GetSpendHeight(const CCoinsViewCache& inputs);
+
#endif // BITCOIN_MAIN_H
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index b682a42e23..5f800474a0 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -94,6 +94,9 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
+ HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
);
+ if (fPruneMode)
+ throw JSONRPCError(RPC_WALLET_ERROR, "Importing keys is disabled in pruned mode");
+
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked();
@@ -166,6 +169,9 @@ UniValue importaddress(const UniValue& params, bool fHelp)
+ HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false")
);
+ if (fPruneMode)
+ throw JSONRPCError(RPC_WALLET_ERROR, "Importing addresses is disabled in pruned mode");
+
LOCK2(cs_main, pwalletMain->cs_wallet);
CScript script;
@@ -236,6 +242,9 @@ UniValue importwallet(const UniValue& params, bool fHelp)
+ HelpExampleRpc("importwallet", "\"test\"")
);
+ if (fPruneMode)
+ throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode");
+
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked();