aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.test.include1
-rw-r--r--src/bitcoin-cli.cpp2
-rw-r--r--src/chainparams.cpp10
-rw-r--r--src/checkpoints.cpp10
-rw-r--r--src/checkpoints.h3
-rw-r--r--src/consensus/params.h1
-rw-r--r--src/init.cpp19
-rw-r--r--src/main.cpp94
-rw-r--r--src/main.h4
-rw-r--r--src/net.cpp32
-rw-r--r--src/net.h12
-rw-r--r--src/primitives/transaction.cpp5
-rw-r--r--src/primitives/transaction.h2
-rw-r--r--src/rpc/server.cpp2
-rw-r--r--src/test/Checkpoints_tests.cpp27
-rw-r--r--src/test/DoS_tests.cpp8
-rw-r--r--src/test/README.md47
-rw-r--r--src/test/bctest.py164
-rwxr-xr-xsrc/test/bitcoin-util-test.py22
-rw-r--r--src/test/mempool_tests.cpp1
-rw-r--r--src/test/net_tests.cpp4
-rw-r--r--src/wallet/wallet.cpp10
-rw-r--r--src/wallet/wallet.h13
23 files changed, 283 insertions, 210 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 5ce1bbb896..4e4cca14ca 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -50,7 +50,6 @@ BITCOIN_TESTS =\
test/bip32_tests.cpp \
test/blockencodings_tests.cpp \
test/bloom_tests.cpp \
- test/Checkpoints_tests.cpp \
test/coins_tests.cpp \
test/compress_tests.cpp \
test/crypto_tests.cpp \
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 2d66448d80..8a2f380e67 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -240,7 +240,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
event_base_free(base);
if (response.status == 0)
- throw CConnectionFailed(strprintf("couldn't connect to server (%d %s)", response.error, http_errorstring(response.error)));
+ throw CConnectionFailed(strprintf("couldn't connect to server\n(make sure server is running and you are connecting to the correct RPC port: %d %s)", response.error, http_errorstring(response.error)));
else if (response.status == HTTP_UNAUTHORIZED)
throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 5850016ae2..a57ab632e4 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -96,6 +96,9 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1479168000; // November 15th, 2016.
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1510704000; // November 15th, 2017.
+ // The best chain should have at least this much work.
+ consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000002cb971dd56d1c583c20f90");
+
/**
* The message start string is designed to be unlikely to occur in normal data.
* The characters are rarely used upper ASCII, not valid as UTF-8, and produce
@@ -191,6 +194,9 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1462060800; // May 1st 2016
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1493596800; // May 1st 2017
+ // The best chain should have at least this much work.
+ consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000000000198b4def2baa9338d6");
+
pchMessageStart[0] = 0x0b;
pchMessageStart[1] = 0x11;
pchMessageStart[2] = 0x09;
@@ -224,6 +230,7 @@ public:
fRequireStandard = false;
fMineBlocksOnDemand = false;
+
checkpointData = (CCheckpointData) {
boost::assign::map_list_of
( 546, uint256S("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")),
@@ -265,6 +272,9 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 999999999999ULL;
+ // The best chain should have at least this much work.
+ consensus.nMinimumChainWork = uint256S("0x00");
+
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xbf;
pchMessageStart[2] = 0xb5;
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index aefddce464..d22c188c16 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -55,16 +55,6 @@ namespace Checkpoints {
return fWorkBefore / (fWorkBefore + fWorkAfter);
}
- int GetTotalBlocksEstimate(const CCheckpointData& data)
- {
- const MapCheckpoints& checkpoints = data.mapCheckpoints;
-
- if (checkpoints.empty())
- return 0;
-
- return checkpoints.rbegin()->first;
- }
-
CBlockIndex* GetLastCheckpoint(const CCheckpointData& data)
{
const MapCheckpoints& checkpoints = data.mapCheckpoints;
diff --git a/src/checkpoints.h b/src/checkpoints.h
index cd25ea5379..04346f35ff 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -19,9 +19,6 @@ struct CCheckpointData;
namespace Checkpoints
{
-//! Return conservative estimate of total number of blocks, 0 if unknown
-int GetTotalBlocksEstimate(const CCheckpointData& data);
-
//! Returns last CBlockIndex* in mapBlockIndex that is a checkpoint
CBlockIndex* GetLastCheckpoint(const CCheckpointData& data);
diff --git a/src/consensus/params.h b/src/consensus/params.h
index 0e73cace83..20efc68ade 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -61,6 +61,7 @@ struct Params {
int64_t nPowTargetSpacing;
int64_t nPowTargetTimespan;
int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
+ uint256 nMinimumChainWork;
};
} // namespace Consensus
diff --git a/src/init.cpp b/src/init.cpp
index efaf821f4f..31e3efb459 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -1103,6 +1103,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
return false;
#endif
// ********************************************************* Step 6: network initialization
+ // Note that we absolutely cannot open any actual connections
+ // until the very end ("start node") as the UTXO/block state
+ // is not yet setup and may end up being set up twice if we
+ // need to reindex later.
assert(!g_connman);
g_connman = std::unique_ptr<CConnman>(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max())));
@@ -1323,7 +1327,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
CleanupBlockRevFiles();
}
- if (!LoadBlockIndex()) {
+ if (!LoadBlockIndex(chainparams)) {
strLoadError = _("Error loading block database");
break;
}
@@ -1496,13 +1500,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
uiInterface.NotifyBlockTip.disconnect(BlockNotifyGenesisWait);
}
-#ifdef ENABLE_WALLET
- // Add wallet transactions that aren't already in a block to mempool
- // Do this here as mempool requires genesis block to be loaded
- if (pwalletMain)
- pwalletMain->ReacceptWalletTransactions();
-#endif
-
// ********************************************************* Step 11: start node
//// debug print
@@ -1540,10 +1537,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
uiInterface.InitMessage(_("Done loading"));
#ifdef ENABLE_WALLET
- if (pwalletMain) {
- // Run a thread to flush wallet periodically
- threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(pwalletMain->strWalletFile)));
- }
+ if (pwalletMain)
+ pwalletMain->postInitProcess(threadGroup);
#endif
return !fRequestShutdown;
diff --git a/src/main.cpp b/src/main.cpp
index 11abc0d175..3f706b1503 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -63,7 +63,7 @@ CCriticalSection cs_main;
BlockMap mapBlockIndex;
CChain chainActive;
CBlockIndex *pindexBestHeader = NULL;
-int64_t nTimeBestReceived = 0;
+int64_t nTimeBestReceived = 0; // Used only to inform the wallet of when we last received a block
CWaitableCriticalSection csBestBlock;
CConditionVariable cvBlockChange;
int nScriptCheckThreads = 0;
@@ -691,6 +691,16 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc
CCoinsViewCache *pcoinsTip = NULL;
CBlockTreeDB *pblocktree = NULL;
+enum FlushStateMode {
+ FLUSH_STATE_NONE,
+ FLUSH_STATE_IF_NEEDED,
+ FLUSH_STATE_PERIODIC,
+ FLUSH_STATE_ALWAYS
+};
+
+// See definition for documentation
+bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode);
+
//////////////////////////////////////////////////////////////////////////////
//
// mapOrphanTransactions
@@ -1581,6 +1591,9 @@ bool AcceptToMemoryPoolWithTime(CTxMemPool& pool, CValidationState &state, const
BOOST_FOREACH(const uint256& hashTx, vHashTxToUncache)
pcoinsTip->Uncache(hashTx);
}
+ // After we've (potentially) uncached entries, ensure our coins cache is still within its size limits
+ CValidationState stateDummy;
+ FlushStateToDisk(stateDummy, FLUSH_STATE_PERIODIC);
return res;
}
@@ -1746,13 +1759,14 @@ bool IsInitialBlockDownload()
return false;
if (fImporting || fReindex)
return true;
- if (fCheckpointsEnabled && chainActive.Height() < Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints()))
+ if (chainActive.Tip() == NULL)
+ return true;
+ if (chainActive.Tip()->nChainWork < UintToArith256(chainParams.GetConsensus().nMinimumChainWork))
return true;
- bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 ||
- std::max(chainActive.Tip()->GetBlockTime(), pindexBestHeader->GetBlockTime()) < GetTime() - nMaxTipAge);
- if (!state)
- latchToFalse.store(true, std::memory_order_relaxed);
- return state;
+ if (chainActive.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge))
+ return true;
+ latchToFalse.store(true, std::memory_order_relaxed);
+ return false;
}
bool fLargeWorkForkFound = false;
@@ -1780,7 +1794,7 @@ void CheckForkWarningConditions()
{
AssertLockHeld(cs_main);
// Before we get past initial download, we cannot reliably alert about forks
- // (we assume we don't get stuck on a fork before the last checkpoint)
+ // (we assume we don't get stuck on a fork before finishing our initial sync)
if (IsInitialBlockDownload())
return;
@@ -2564,13 +2578,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return true;
}
-enum FlushStateMode {
- FLUSH_STATE_NONE,
- FLUSH_STATE_IF_NEEDED,
- FLUSH_STATE_PERIODIC,
- FLUSH_STATE_ALWAYS
-};
-
/**
* Update the on-disk chain state.
* The caches and indexes are flushed depending on the mode we're called with
@@ -2690,7 +2697,6 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
chainActive.SetTip(pindexNew);
// New best block
- nTimeBestReceived = GetTime();
mempool.AddTransactionsUpdated(1);
cvBlockChange.notify_all();
@@ -3675,6 +3681,8 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state
if (ppindex)
*ppindex = pindex;
+ CheckBlockIndex(chainparams.GetConsensus());
+
return true;
}
@@ -3702,6 +3710,11 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
// not process unrequested blocks.
bool fTooFarAhead = (pindex->nHeight > int(chainActive.Height() + MIN_BLOCKS_TO_KEEP));
+ // TODO: Decouple this function from the block download logic by removing fRequested
+ // This requires some new chain datastructure to efficiently look up if a
+ // block is in a chain leading to a candidate for best tip, despite not
+ // being such a candidate itself.
+
// TODO: deal better with return value and error conditions for duplicate
// and unrequested blocks.
if (fAlreadyHave) return true;
@@ -3750,13 +3763,11 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C
{
{
LOCK(cs_main);
- bool fRequested = MarkBlockAsReceived(pblock->GetHash());
- fRequested |= fForceProcessing;
// Store to disk
CBlockIndex *pindex = NULL;
bool fNewBlock = false;
- bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fRequested, dbp, &fNewBlock);
+ bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fForceProcessing, dbp, &fNewBlock);
if (pindex && pfrom) {
mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId();
if (fNewBlock) pfrom->nLastBlockTime = GetTime();
@@ -3972,9 +3983,8 @@ CBlockIndex * InsertBlockIndex(uint256 hash)
return pindexNew;
}
-bool static LoadBlockIndexDB()
+bool static LoadBlockIndexDB(const CChainParams& chainparams)
{
- const CChainParams& chainparams = Params();
if (!pblocktree->LoadBlockIndexGuts(InsertBlockIndex))
return false;
@@ -4269,6 +4279,9 @@ bool RewindBlockIndex(const CChainParams& params)
return true;
}
+// May NOT be used after any connections are up as much
+// of the peer-processing logic assumes a consistent
+// block index state
void UnloadBlockIndex()
{
LOCK(cs_main);
@@ -4279,18 +4292,12 @@ void UnloadBlockIndex()
mempool.clear();
mapOrphanTransactions.clear();
mapOrphanTransactionsByPrev.clear();
- nSyncStarted = 0;
mapBlocksUnlinked.clear();
vinfoBlockFile.clear();
nLastBlockFile = 0;
nBlockSequenceId = 1;
- mapBlockSource.clear();
- mapBlocksInFlight.clear();
- nPreferredDownload = 0;
setDirtyBlockIndex.clear();
setDirtyFileInfo.clear();
- mapNodeState.clear();
- recentRejects.reset(NULL);
versionbitscache.Clear();
for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
warningcache[b].clear();
@@ -4303,10 +4310,10 @@ void UnloadBlockIndex()
fHavePruned = false;
}
-bool LoadBlockIndex()
+bool LoadBlockIndex(const CChainParams& chainparams)
{
// Load block index from databases
- if (!fReindex && !LoadBlockIndexDB())
+ if (!fReindex && !LoadBlockIndexDB(chainparams))
return false;
return true;
}
@@ -4315,9 +4322,6 @@ bool InitBlockIndex(const CChainParams& chainparams)
{
LOCK(cs_main);
- // Initialize global variables that cannot be constructed at startup.
- recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));
-
// Check whether we're already initialized
if (chainActive.Genesis() != NULL)
return true;
@@ -4706,6 +4710,11 @@ std::string GetWarnings(const std::string& strFor)
// blockchain -> download logic notification
//
+PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn) : connman(connmanIn) {
+ // Initialize global variables that cannot be constructed at startup.
+ recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));
+}
+
void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
const int nNewHeight = pindexNew->nHeight;
connman->SetBestHeight(nNewHeight);
@@ -4732,6 +4741,8 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB
}
});
}
+
+ nTimeBestReceived = GetTime();
}
void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationState& state) {
@@ -5690,7 +5701,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
Misbehaving(pfrom->GetId(), nDoS);
}
}
- FlushStateToDisk(state, FLUSH_STATE_PERIODIC);
}
@@ -5826,8 +5836,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams, connman);
}
}
-
- CheckBlockIndex(chainparams.GetConsensus());
}
else if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex) // Ignore blocks received while importing
@@ -5859,12 +5867,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
std::vector<CInv> invs;
invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()), resp.blockhash));
pfrom->PushMessage(NetMsgType::GETDATA, invs);
- } else
+ } else {
+ MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer
fBlockRead = true;
+ }
} // Don't hold cs_main when we call into ProcessNewBlock
if (fBlockRead) {
CValidationState state;
- ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL);
+ // Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
+ // even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
+ ProcessNewBlock(state, chainparams, pfrom, &block, true, NULL);
int nDoS;
if (state.IsInvalid(nDoS)) {
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
@@ -6020,8 +6032,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
}
}
-
- CheckBlockIndex(chainparams.GetConsensus());
}
NotifyHeaderTip();
@@ -6040,6 +6050,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Such an unrequested block may still be processed, subject to the
// conditions in AcceptBlock().
bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload();
+ {
+ LOCK(cs_main);
+ // Also always process if we requested the block explicitly, as we may
+ // need it even though it is not a candidate for a new best tip.
+ forceProcessing |= MarkBlockAsReceived(block.GetHash());
+ }
ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL);
int nDoS;
if (state.IsInvalid(nDoS)) {
diff --git a/src/main.h b/src/main.h
index 4c6af95142..e80314a64b 100644
--- a/src/main.h
+++ b/src/main.h
@@ -237,7 +237,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, CDiskB
/** Initialize a new block tree database + block data on disk */
bool InitBlockIndex(const CChainParams& chainparams);
/** Load the block tree and coins database from disk */
-bool LoadBlockIndex();
+bool LoadBlockIndex(const CChainParams& chainparams);
/** Unload database information */
void UnloadBlockIndex();
/** Run an instance of the script checking thread */
@@ -552,7 +552,7 @@ private:
CConnman* connman;
public:
- PeerLogicValidation(CConnman* connmanIn) : connman(connmanIn) {}
+ PeerLogicValidation(CConnman* connmanIn);
virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload);
virtual void BlockChecked(const CBlock& block, const CValidationState& state);
diff --git a/src/net.cpp b/src/net.cpp
index 48ba9588d9..18d25cbcd1 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -64,6 +64,7 @@
const static std::string NET_MESSAGE_COMMAND_OTHER = "*other*";
static const uint64_t RANDOMIZER_ID_NETGROUP = 0x6c0edd8036ef4036ULL; // SHA256("netgroup")[0:8]
+static const uint64_t RANDOMIZER_ID_LOCALHOSTNONCE = 0xd93e69e2bbfa5735ULL; // SHA256("localhostnonce")[0:8]
//
// Global state variables
//
@@ -389,7 +390,10 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
addrman.Attempt(addrConnect, fCountFailure);
// Add node
- CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), pszDest ? pszDest : "", false);
+ NodeId id = GetNewNodeId();
+ uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
+ CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, pszDest ? pszDest : "", false);
+
GetNodeSignals().InitializeNode(pnode->GetId(), pnode);
pnode->AddRef();
@@ -1024,7 +1028,10 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
}
}
- CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), "", true);
+ NodeId id = GetNewNodeId();
+ uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
+
+ CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, "", true);
GetNodeSignals().InitializeNode(pnode->GetId(), pnode);
pnode->AddRef();
pnode->fWhitelisted = whitelisted;
@@ -2118,7 +2125,11 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st
if (pnodeLocalHost == NULL) {
CNetAddr local;
LookupHost("127.0.0.1", local, false);
- pnodeLocalHost = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices), 0);
+
+ NodeId id = GetNewNodeId();
+ uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
+
+ pnodeLocalHost = new CNode(id, nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService(local, 0), nLocalServices), 0, nonce);
GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost);
}
@@ -2509,12 +2520,17 @@ void CNode::Fuzz(int nChance)
unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; }
-CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, const std::string& addrNameIn, bool fInboundIn) :
+CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const std::string& addrNameIn, bool fInboundIn) :
ssSend(SER_NETWORK, INIT_PROTO_VERSION),
addr(addrIn),
+ fInbound(fInboundIn),
+ id(idIn),
nKeyedNetGroup(nKeyedNetGroupIn),
addrKnown(5000, 0.001),
- filterInventoryKnown(50000, 0.000001)
+ filterInventoryKnown(50000, 0.000001),
+ nLocalHostNonce(nLocalHostNonceIn),
+ nLocalServices(nLocalServicesIn),
+ nMyStartingHeight(nMyStartingHeightIn)
{
nServices = NODE_NONE;
nServicesExpected = NODE_NONE;
@@ -2533,7 +2549,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
fOneShot = false;
fClient = false; // set by version message
fFeeler = false;
- fInbound = fInboundIn;
fNetworkNode = false;
fSuccessfullyConnected = false;
fDisconnect = false;
@@ -2562,12 +2577,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
minFeeFilter = 0;
lastSentFeeFilter = 0;
nextSendTimeFeeFilter = 0;
- id = idIn;
nOptimisticBytesWritten = 0;
- nLocalServices = nLocalServicesIn;
-
- GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce));
- nMyStartingHeight = nMyStartingHeightIn;
BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes())
mapRecvBytesPerMsgCmd[msg] = 0;
diff --git a/src/net.h b/src/net.h
index 58b492e592..bfce516237 100644
--- a/src/net.h
+++ b/src/net.h
@@ -589,7 +589,7 @@ public:
bool fFeeler; // If true this node is being used as a short lived feeler.
bool fOneShot;
bool fClient;
- bool fInbound;
+ const bool fInbound;
bool fNetworkNode;
bool fSuccessfullyConnected;
bool fDisconnect;
@@ -603,7 +603,7 @@ public:
CCriticalSection cs_filter;
CBloomFilter* pfilter;
int nRefCount;
- NodeId id;
+ const NodeId id;
const uint64_t nKeyedNetGroup;
protected:
@@ -669,7 +669,7 @@ public:
CAmount lastSentFeeFilter;
int64_t nextSendTimeFeeFilter;
- CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, const std::string &addrNameIn = "", bool fInboundIn = false);
+ CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const std::string &addrNameIn = "", bool fInboundIn = false);
~CNode();
private:
@@ -677,10 +677,10 @@ private:
void operator=(const CNode&);
- uint64_t nLocalHostNonce;
+ const uint64_t nLocalHostNonce;
// Services offered to this peer
- ServiceFlags nLocalServices;
- int nMyStartingHeight;
+ const ServiceFlags nLocalServices;
+ const int nMyStartingHeight;
public:
NodeId GetId() const {
diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp
index 4afbe99fd3..7acdac17f2 100644
--- a/src/primitives/transaction.cpp
+++ b/src/primitives/transaction.cpp
@@ -49,11 +49,6 @@ CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn)
scriptPubKey = scriptPubKeyIn;
}
-uint256 CTxOut::GetHash() const
-{
- return SerializeHash(*this);
-}
-
std::string CTxOut::ToString() const
{
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 16c2e5c454..1afeb87039 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -160,8 +160,6 @@ public:
return (nValue == -1);
}
- uint256 GetHash() const;
-
CAmount GetDustThreshold(const CFeeRate &minRelayTxFee) const
{
// "Dust" is defined in terms of CTransaction::minRelayTxFee,
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 29d0bee1b2..164e0f00e2 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -147,6 +147,8 @@ uint256 ParseHashV(const UniValue& v, string strName)
strHex = v.get_str();
if (!IsHex(strHex)) // Note: IsHex("") is false
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
+ if (64 != strHex.length())
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d)", strName, 64, strHex.length()));
uint256 result;
result.SetHex(strHex);
return result;
diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp
deleted file mode 100644
index 1b7d368e13..0000000000
--- a/src/test/Checkpoints_tests.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-//
-// Unit tests for block-chain checkpoints
-//
-
-#include "checkpoints.h"
-
-#include "uint256.h"
-#include "test/test_bitcoin.h"
-#include "chainparams.h"
-
-#include <boost/test/unit_test.hpp>
-
-using namespace std;
-
-BOOST_FIXTURE_TEST_SUITE(Checkpoints_tests, BasicTestingSetup)
-
-BOOST_AUTO_TEST_CASE(sanity)
-{
- const CCheckpointData& checkpoints = Params(CBaseChainParams::MAIN).Checkpoints();
- BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate(checkpoints) >= 134444);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index 97abeb7211..4aa7166815 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
{
connman->ClearBanned();
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, "", true);
+ CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, "", true);
GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1);
dummyNode1.nVersion = 1;
Misbehaving(dummyNode1.GetId(), 100); // Should get banned
@@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
CAddress addr2(ip(0xa0b0c002), NODE_NONE);
- CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, "", true);
+ CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, "", true);
GetNodeSignals().InitializeNode(dummyNode2.GetId(), &dummyNode2);
dummyNode2.nVersion = 1;
Misbehaving(dummyNode2.GetId(), 50);
@@ -74,7 +74,7 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
connman->ClearBanned();
mapArgs["-banscore"] = "111"; // because 11 is my favorite number
CAddress addr1(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, "", true);
+ CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, "", true);
GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1);
dummyNode1.nVersion = 1;
Misbehaving(dummyNode1.GetId(), 100);
@@ -96,7 +96,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
SetMockTime(nStartTime); // Overrides future calls to GetTime()
CAddress addr(ip(0xa0b0c001), NODE_NONE);
- CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, "", true);
+ CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, "", true);
GetNodeSignals().InitializeNode(dummyNode.GetId(), &dummyNode);
dummyNode.nVersion = 1;
diff --git a/src/test/README.md b/src/test/README.md
index 3afdefe5fc..8f99804e10 100644
--- a/src/test/README.md
+++ b/src/test/README.md
@@ -1,4 +1,36 @@
-# Notes
+### Compiling/running unit tests
+
+Unit tests will be automatically compiled if dependencies were met in `./configure`
+and tests weren't explicitly disabled.
+
+After configuring, they can be run with `make check`.
+
+To run the bitcoind tests manually, launch `src/test/test_bitcoin`.
+
+To add more bitcoind tests, add `BOOST_AUTO_TEST_CASE` functions to the existing
+.cpp files in the `test/` directory or add new .cpp files that
+implement new BOOST_AUTO_TEST_SUITE sections.
+
+To run the bitcoin-qt tests manually, launch `src/qt/test/test_bitcoin-qt`
+
+To add more bitcoin-qt tests, add them to the `src/qt/test/` directory and
+the `src/qt/test/test_main.cpp` file.
+
+### Running individual tests
+
+test_bitcoin has some built-in command-line arguments; for
+example, to run just the getarg_tests verbosely:
+
+ test_bitcoin --log_level=all --run_test=getarg_tests
+
+... or to run just the doubledash test:
+
+ test_bitcoin --run_test=getarg_tests/doubledash
+
+Run `test_bitcoin --help` for the full list.
+
+### Note on adding test cases
+
The sources in this directory are unit test cases. Boost includes a
unit testing framework, and since bitcoin already uses boost, it makes
sense to simply use this framework rather than require developers to
@@ -19,17 +51,6 @@ For further reading, I found the following website to be helpful in
explaining how the boost unit test framework works:
[http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/](http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/).
-test_bitcoin has some built-in command-line arguments; for
-example, to run just the getarg_tests verbosely:
-
- test_bitcoin --log_level=all --run_test=getarg_tests
-
-... or to run just the doubledash test:
-
- test_bitcoin --run_test=getarg_tests/doubledash
-
-Run `test_bitcoin --help` for the full list.
-
### bitcoin-util-test.py
The test directory also contains the bitcoin-util-test.py tool, which tests bitcoin utils (currently just bitcoin-tx). This test gets run automatically during the `make check` build process. It is also possible to run the test manually from the src directory:
@@ -37,4 +58,4 @@ The test directory also contains the bitcoin-util-test.py tool, which tests bitc
```
test/bitcoin-util-test.py --srcdir=[current directory]
-``` \ No newline at end of file
+```
diff --git a/src/test/bctest.py b/src/test/bctest.py
index eab4fb734a..47cff98bca 100644
--- a/src/test/bctest.py
+++ b/src/test/bctest.py
@@ -1,4 +1,5 @@
# Copyright 2014 BitPay, Inc.
+# Copyright 2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from __future__ import division,print_function,unicode_literals
@@ -7,79 +8,114 @@ import os
import json
import sys
import binascii
+import difflib
+import logging
def parse_output(a, fmt):
- if fmt == 'json': # json: compare parsed data
- return json.loads(a)
- elif fmt == 'hex': # hex: parse and compare binary data
- return binascii.a2b_hex(a.strip())
- else:
- raise NotImplementedError("Don't know how to compare %s" % fmt)
+ """Parse the output according to specified format.
+
+ Raise an error if the output can't be parsed."""
+ if fmt == 'json': # json: compare parsed data
+ return json.loads(a)
+ elif fmt == 'hex': # hex: parse and compare binary data
+ return binascii.a2b_hex(a.strip())
+ else:
+ raise NotImplementedError("Don't know how to compare %s" % fmt)
def bctest(testDir, testObj, exeext):
+ """Runs a single test, comparing output and RC to expected output and RC.
+
+ Raises an error if input can't be read, executable fails, or output/RC
+ are not as expected. Error is caught by bctester() and reported.
+ """
+ # Get the exec names and arguments
+ execprog = testObj['exec'] + exeext
+ execargs = testObj['args']
+ execrun = [execprog] + execargs
+
+ # Read the input data (if there is any)
+ stdinCfg = None
+ inputData = None
+ if "input" in testObj:
+ filename = testDir + "/" + testObj['input']
+ inputData = open(filename).read()
+ stdinCfg = subprocess.PIPE
- execprog = testObj['exec'] + exeext
- execargs = testObj['args']
- execrun = [execprog] + execargs
- stdinCfg = None
- inputData = None
- if "input" in testObj:
- filename = testDir + "/" + testObj['input']
- inputData = open(filename).read()
- stdinCfg = subprocess.PIPE
+ # Read the expected output data (if there is any)
+ outputFn = None
+ outputData = None
+ if "output_cmp" in testObj:
+ outputFn = testObj['output_cmp']
+ outputType = os.path.splitext(outputFn)[1][1:] # output type from file extension (determines how to compare)
+ try:
+ outputData = open(testDir + "/" + outputFn).read()
+ except:
+ logging.error("Output file " + outputFn + " can not be opened")
+ raise
+ if not outputData:
+ logging.error("Output data missing for " + outputFn)
+ raise Exception
- outputFn = None
- outputData = None
- if "output_cmp" in testObj:
- outputFn = testObj['output_cmp']
- outputType = os.path.splitext(outputFn)[1][1:] # output type from file extension (determines how to compare)
- outputData = open(testDir + "/" + outputFn).read()
- if not outputData:
- print("Output data missing for " + outputFn)
- sys.exit(1)
- proc = subprocess.Popen(execrun, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE,universal_newlines=True)
- try:
- outs = proc.communicate(input=inputData)
- except OSError:
- print("OSError, Failed to execute " + execprog)
- sys.exit(1)
+ # Run the test
+ proc = subprocess.Popen(execrun, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE,universal_newlines=True)
+ try:
+ outs = proc.communicate(input=inputData)
+ except OSError:
+ logging.error("OSError, Failed to execute " + execprog)
+ raise
- if outputData:
- try:
- a_parsed = parse_output(outs[0], outputType)
- except Exception as e:
- print('Error parsing command output as %s: %s' % (outputType,e))
- sys.exit(1)
- try:
- b_parsed = parse_output(outputData, outputType)
- except Exception as e:
- print('Error parsing expected output %s as %s: %s' % (outputFn,outputType,e))
- sys.exit(1)
- if a_parsed != b_parsed:
- print("Output data mismatch for " + outputFn + " (format " + outputType + ")")
- sys.exit(1)
- if outs[0] != outputData:
- print("Output formatting mismatch for " + outputFn + " (format " + outputType + ")")
- sys.exit(1)
+ if outputData:
+ # Parse command output and expected output
+ try:
+ a_parsed = parse_output(outs[0], outputType)
+ except Exception as e:
+ logging.error('Error parsing command output as %s: %s' % (outputType,e))
+ raise
+ try:
+ b_parsed = parse_output(outputData, outputType)
+ except Exception as e:
+ logging.error('Error parsing expected output %s as %s: %s' % (outputFn,outputType,e))
+ raise
+ # Compare data
+ if a_parsed != b_parsed:
+ logging.error("Output data mismatch for " + outputFn + " (format " + outputType + ")")
+ raise Exception
+ # Compare formatting
+ if outs[0] != outputData:
+ error_message = "Output formatting mismatch for " + outputFn + ":\n"
+ error_message += "".join(difflib.context_diff(outputData.splitlines(True),
+ outs[0].splitlines(True),
+ fromfile=outputFn,
+ tofile="returned"))
+ logging.error(error_message)
+ raise Exception
- wantRC = 0
- if "return_code" in testObj:
- wantRC = testObj['return_code']
- if proc.returncode != wantRC:
- print("Return code mismatch for " + outputFn)
- sys.exit(1)
+ # Compare the return code to the expected return code
+ wantRC = 0
+ if "return_code" in testObj:
+ wantRC = testObj['return_code']
+ if proc.returncode != wantRC:
+ logging.error("Return code mismatch for " + outputFn)
+ raise Exception
-def bctester(testDir, input_basename, buildenv, verbose = False):
- input_filename = testDir + "/" + input_basename
- raw_data = open(input_filename).read()
- input_data = json.loads(raw_data)
+def bctester(testDir, input_basename, buildenv):
+ """ Loads and parses the input file, runs all tests and reports results"""
+ input_filename = testDir + "/" + input_basename
+ raw_data = open(input_filename).read()
+ input_data = json.loads(raw_data)
- for testObj in input_data:
- if verbose and "description" in testObj:
- print ("Testing: " + testObj["description"])
- bctest(testDir, testObj, buildenv.exeext)
- if verbose and "description" in testObj:
- print ("PASS")
+ failed_testcases = []
- sys.exit(0)
+ for testObj in input_data:
+ try:
+ bctest(testDir, testObj, buildenv.exeext)
+ logging.info("PASSED: " + testObj["description"])
+ except:
+ logging.info("FAILED: " + testObj["description"])
+ failed_testcases.append(testObj["description"])
+ if failed_testcases:
+ logging.error("FAILED TESTCASES: [" + ", ".join(failed_testcases) + "]")
+ sys.exit(1)
+ else:
+ sys.exit(0)
diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py
index 3099506d6d..eeb05c0b88 100755
--- a/src/test/bitcoin-util-test.py
+++ b/src/test/bitcoin-util-test.py
@@ -1,12 +1,15 @@
#!/usr/bin/env python
# Copyright 2014 BitPay, Inc.
+# Copyright 2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from __future__ import division,print_function,unicode_literals
import os
+import sys
import bctest
import buildenv
import argparse
+import logging
help_text="""Test framework for bitcoin utils.
@@ -14,14 +17,16 @@ Runs automatically during `make check`.
Can also be run manually from the src directory by specifiying the source directory:
-test/bitcoin-util-test.py --src=[srcdir]
+test/bitcoin-util-test.py --srcdir='srcdir' [--verbose]
"""
-
if __name__ == '__main__':
- verbose = False
+ # Try to get the source directory from the environment variables. This will
+ # be set for `make check` automated runs. If environment variable is not set,
+ # then get the source directory from command line args.
try:
srcdir = os.environ["srcdir"]
+ verbose = False
except:
parser = argparse.ArgumentParser(description=help_text)
parser.add_argument('-s', '--srcdir')
@@ -29,4 +34,13 @@ if __name__ == '__main__':
args = parser.parse_args()
srcdir = args.srcdir
verbose = args.verbose
- bctest.bctester(srcdir + "/test/data", "bitcoin-util-test.json", buildenv, verbose = verbose)
+
+ if verbose:
+ level = logging.DEBUG
+ else:
+ level = logging.ERROR
+ formatter = '%(asctime)s - %(levelname)s - %(message)s'
+ # Add the format/level to the logger
+ logging.basicConfig(format = formatter, level=level)
+
+ bctest.bctester(srcdir + "/test/data", "bitcoin-util-test.json", buildenv)
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 555d36faac..a73dbe725c 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -547,7 +547,6 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool));
std::vector<CTransaction> vtx;
- std::vector<std::shared_ptr<const CTransaction>> conflicts;
SetMockTime(42);
SetMockTime(42 + CTxMemPool::ROLLING_FEE_HALFLIFE);
BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index f4b5768693..e0460109d5 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -164,12 +164,12 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
bool fInboundIn = false;
// Test that fFeeler is false by default.
- CNode* pnode1 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, 0, pszDest, fInboundIn);
+ CNode* pnode1 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, pszDest, fInboundIn);
BOOST_CHECK(pnode1->fInbound == false);
BOOST_CHECK(pnode1->fFeeler == false);
fInboundIn = true;
- CNode* pnode2 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, 1, pszDest, fInboundIn);
+ CNode* pnode2 = new CNode(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, pszDest, fInboundIn);
BOOST_CHECK(pnode2->fInbound == true);
BOOST_CHECK(pnode2->fFeeler == false);
}
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 9e19138099..c2bac6e330 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3549,6 +3549,16 @@ bool CWallet::InitLoadWallet()
return true;
}
+void CWallet::postInitProcess(boost::thread_group& threadGroup)
+{
+ // Add wallet transactions that aren't already in a block to mempool
+ // Do this here as mempool requires genesis block to be loaded
+ ReacceptWalletTransactions();
+
+ // Run a thread to flush wallet periodically
+ threadGroup.create_thread(boost::bind(&ThreadFlushWalletDB, boost::ref(this->strWalletFile)));
+}
+
bool CWallet::ParameterInteraction()
{
if (GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET))
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index c33a6ca91f..57b17d87ad 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -27,6 +27,7 @@
#include <vector>
#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
extern CWallet* pwalletMain;
@@ -53,7 +54,7 @@ static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true;
//! Default for -sendfreetransactions
static const bool DEFAULT_SEND_FREE_TRANSACTIONS = false;
//! -txconfirmtarget default
-static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 2;
+static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6;
//! -walletrbf default
static const bool DEFAULT_WALLET_RBF = false;
//! Largest (in bytes) free transaction we're willing to create
@@ -133,7 +134,7 @@ struct CRecipient
typedef std::map<std::string, std::string> mapValue_t;
-static void ReadOrderPos(int64_t& nOrderPos, mapValue_t& mapValue)
+static inline void ReadOrderPos(int64_t& nOrderPos, mapValue_t& mapValue)
{
if (!mapValue.count("n"))
{
@@ -144,7 +145,7 @@ static void ReadOrderPos(int64_t& nOrderPos, mapValue_t& mapValue)
}
-static void WriteOrderPos(const int64_t& nOrderPos, mapValue_t& mapValue)
+static inline void WriteOrderPos(const int64_t& nOrderPos, mapValue_t& mapValue)
{
if (nOrderPos == -1)
return;
@@ -912,6 +913,12 @@ public:
/* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
static bool InitLoadWallet();
+ /**
+ * Wallet post-init setup
+ * Gives the wallet a chance to register repetitive tasks and complete post-init tasks
+ */
+ void postInitProcess(boost::thread_group& threadGroup);
+
/* Wallets parameter interaction */
static bool ParameterInteraction();