aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/httprpc.cpp4
-rw-r--r--src/init.cpp26
-rw-r--r--src/main.cpp18
-rw-r--r--src/main.h2
-rw-r--r--src/policy/policy.cpp3
-rw-r--r--src/qt/intro.cpp20
-rw-r--r--src/qt/rpcconsole.cpp6
-rw-r--r--src/reverselock.h5
-rw-r--r--src/rpcserver.cpp22
-rw-r--r--src/rpcserver.h10
-rw-r--r--src/test/reverselock_tests.cpp16
-rw-r--r--src/wallet/test/wallet_tests.cpp25
-rw-r--r--src/wallet/wallet.cpp7
-rw-r--r--src/wallet/wallet.h164
-rw-r--r--src/wallet/walletdb.cpp13
15 files changed, 199 insertions, 142 deletions
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 2920aa26f7..1466dc0cbf 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -226,7 +226,7 @@ bool StartHTTPRPC()
assert(EventBase());
httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase());
- RPCRegisterTimerInterface(httpRPCTimerInterface);
+ RPCSetTimerInterface(httpRPCTimerInterface);
return true;
}
@@ -240,7 +240,7 @@ void StopHTTPRPC()
LogPrint("rpc", "Stopping HTTP RPC server\n");
UnregisterHTTPHandler("/", true);
if (httpRPCTimerInterface) {
- RPCUnregisterTimerInterface(httpRPCTimerInterface);
+ RPCUnsetTimerInterface(httpRPCTimerInterface);
delete httpRPCTimerInterface;
httpRPCTimerInterface = 0;
}
diff --git a/src/init.cpp b/src/init.cpp
index ba85a7972e..374e756abd 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -476,6 +476,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageGroup(_("Node relay options:"));
if (showDebug)
strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !Params(CBaseChainParams::TESTNET).RequireStandard()));
+ strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Minimum bytes per sigop in transactions we relay and mine (default: %u)"), DEFAULT_BYTES_PER_SIGOP));
strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER));
strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY));
@@ -750,6 +751,16 @@ void InitParameterInteraction()
}
}
+static std::string ResolveErrMsg(const char * const optname, const std::string& strBind)
+{
+ return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind);
+}
+
+static std::string AmountErrMsg(const char * const optname, const std::string& strValue)
+{
+ return strprintf(_("Invalid amount for -%s=<amount>: '%s'"), optname, strValue);
+}
+
void InitLogging()
{
fPrintToConsole = GetBoolArg("-printtoconsole", false);
@@ -933,12 +944,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0)
::minRelayTxFee = CFeeRate(n);
else
- return InitError(strprintf(_("Invalid amount for -minrelaytxfee=<amount>: '%s'"), mapArgs["-minrelaytxfee"]));
+ return InitError(AmountErrMsg("minrelaytxfee", mapArgs["-minrelaytxfee"]));
}
fRequireStandard = !GetBoolArg("-acceptnonstdtxn", !Params().RequireStandard());
if (Params().RequireStandard() && !fRequireStandard)
return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString()));
+ nBytesPerSigOp = GetArg("-bytespersigop", nBytesPerSigOp);
#ifdef ENABLE_WALLET
if (mapArgs.count("-mintxfee"))
@@ -947,7 +959,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0)
CWallet::minTxFee = CFeeRate(n);
else
- return InitError(strprintf(_("Invalid amount for -mintxfee=<amount>: '%s'"), mapArgs["-mintxfee"]));
+ return InitError(AmountErrMsg("mintxfee", mapArgs["-mintxfee"]));
}
if (mapArgs.count("-fallbackfee"))
{
@@ -962,7 +974,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
{
CAmount nFeePerK = 0;
if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK))
- return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s'"), mapArgs["-paytxfee"]));
+ return InitError(AmountErrMsg("paytxfee", mapArgs["-paytxfee"]));
if (nFeePerK > nHighTransactionFeeWarning)
InitWarning(_("-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction."));
payTxFee = CFeeRate(nFeePerK, 1000);
@@ -976,7 +988,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
{
CAmount nMaxFee = 0;
if (!ParseMoney(mapArgs["-maxtxfee"], nMaxFee))
- return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s'"), mapArgs["-maptxfee"]));
+ return InitError(AmountErrMsg("maxtxfee", mapArgs["-maptxfee"]));
if (nMaxFee > nHighTransactionMaxFeeWarning)
InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
maxTxFee = nMaxFee;
@@ -1188,13 +1200,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-bind"]) {
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
- return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind));
+ return InitError(ResolveErrMsg("bind", strBind));
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
}
BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-whitebind"]) {
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, 0, false))
- return InitError(strprintf(_("Cannot resolve -whitebind address: '%s'"), strBind));
+ return InitError(ResolveErrMsg("whitebind", strBind));
if (addrBind.GetPort() == 0)
return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind));
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
@@ -1214,7 +1226,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-externalip"]) {
CService addrLocal(strAddr, GetListenPort(), fNameLookup);
if (!addrLocal.IsValid())
- return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr));
+ return InitError(ResolveErrMsg("externalip", strAddr));
AddLocal(CService(strAddr, GetListenPort(), fNameLookup), LOCAL_MANUAL);
}
}
diff --git a/src/main.cpp b/src/main.cpp
index c058843ae3..06374cc1b6 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -69,6 +69,7 @@ bool fHavePruned = false;
bool fPruneMode = false;
bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
bool fRequireStandard = true;
+unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
size_t nCoinCacheUsage = 5000 * 300;
@@ -929,16 +930,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
if (fRequireStandard && !AreInputsStandard(tx, view))
return state.Invalid(false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs");
- // Check that the transaction doesn't have an excessive number of
- // sigops, making it impossible to mine. Since the coinbase transaction
- // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than
- // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than
- // merely non-standard transaction.
unsigned int nSigOps = GetLegacySigOpCount(tx);
nSigOps += GetP2SHSigOpCount(tx, view);
- if (nSigOps > MAX_STANDARD_TX_SIGOPS)
- return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false,
- strprintf("%d > %d", nSigOps, MAX_STANDARD_TX_SIGOPS));
CAmount nValueOut = tx.GetValueOut();
CAmount nFees = nValueIn-nValueOut;
@@ -964,6 +957,15 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps);
unsigned int nSize = entry.GetTxSize();
+ // Check that the transaction doesn't have an excessive number of
+ // sigops, making it impossible to mine. Since the coinbase transaction
+ // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than
+ // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than
+ // merely non-standard transaction.
+ if ((nSigOps > MAX_STANDARD_TX_SIGOPS) || (nBytesPerSigOp && nSigOps > nSize / nBytesPerSigOp))
+ return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false,
+ strprintf("%d", nSigOps));
+
CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
diff --git a/src/main.h b/src/main.h
index cadd281c89..cefaedabf5 100644
--- a/src/main.h
+++ b/src/main.h
@@ -100,6 +100,7 @@ static const bool DEFAULT_RELAYPRIORITY = true;
/** Default for -permitbaremultisig */
static const bool DEFAULT_PERMIT_BAREMULTISIG = true;
+static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;
static const bool DEFAULT_CHECKPOINTS_ENABLED = true;
static const bool DEFAULT_TXINDEX = false;
static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;
@@ -130,6 +131,7 @@ extern int nScriptCheckThreads;
extern bool fTxIndex;
extern bool fIsBareMultisigStd;
extern bool fRequireStandard;
+extern unsigned int nBytesPerSigOp;
extern bool fCheckBlockIndex;
extern bool fCheckpointsEnabled;
extern size_t nCoinCacheUsage;
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 273a482fa1..019df72279 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -23,9 +23,6 @@
* 2. P2SH scripts with a crazy number of expensive
* CHECKSIG/CHECKMULTISIG operations
*
- * Check transaction inputs, and make sure any
- * pay-to-script-hash transactions are evaluating IsStandard scripts
- *
* Why bother? To avoid denial-of-service attacks; an attacker
* can submit a standard HASH... OP_EQUAL transaction,
* which will get accepted into blocks. The redemption
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index e0b84ba13f..f324c6dc5a 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -15,9 +15,15 @@
#include <QSettings>
#include <QMessageBox>
-/* Minimum free space (in bytes) needed for data directory */
+#include <cmath>
+
static const uint64_t GB_BYTES = 1000000000LL;
-static const uint64_t BLOCK_CHAIN_SIZE = 20LL * GB_BYTES;
+/* Minimum free space (in GB) needed for data directory */
+static const uint64_t BLOCK_CHAIN_SIZE = 80;
+/* Minimum free space (in GB) needed for data directory when pruned; Does not include prune target */
+static const uint64_t CHAIN_STATE_SIZE = 2;
+/* Total required space (in GB) depending on user choice (prune, not prune) */
+static uint64_t requiredSpace;
/* Check free space asynchronously to prevent hanging the UI thread.
@@ -112,7 +118,11 @@ Intro::Intro(QWidget *parent) :
signalled(false)
{
ui->setupUi(this);
- ui->sizeWarningLabel->setText(ui->sizeWarningLabel->text().arg(BLOCK_CHAIN_SIZE/GB_BYTES));
+ uint64_t pruneTarget = std::max<int64_t>(0, GetArg("-prune", 0));
+ requiredSpace = BLOCK_CHAIN_SIZE;
+ if (pruneTarget)
+ requiredSpace = CHAIN_STATE_SIZE + std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES);
+ ui->sizeWarningLabel->setText(ui->sizeWarningLabel->text().arg(requiredSpace));
startThread();
}
@@ -216,9 +226,9 @@ void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable
ui->freeSpace->setText("");
} else {
QString freeString = tr("%n GB of free space available", "", bytesAvailable/GB_BYTES);
- if(bytesAvailable < BLOCK_CHAIN_SIZE)
+ if(bytesAvailable < requiredSpace * GB_BYTES)
{
- freeString += " " + tr("(of %n GB needed)", "", BLOCK_CHAIN_SIZE/GB_BYTES);
+ freeString += " " + tr("(of %n GB needed)", "", requiredSpace);
ui->freeSpace->setStyleSheet("QLabel { color: #800000 }");
} else {
ui->freeSpace->setStyleSheet("");
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 4c869b9ac5..7178bc00e6 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -278,7 +278,9 @@ RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) :
#endif
// Register RPC timer interface
rpcTimerInterface = new QtRPCTimerInterface();
- RPCRegisterTimerInterface(rpcTimerInterface);
+ // avoid accidentally overwriting an existing, non QTThread
+ // based timer interface
+ RPCSetTimerInterfaceIfUnset(rpcTimerInterface);
startExecutor();
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
@@ -293,7 +295,7 @@ RPCConsole::~RPCConsole()
{
GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this);
Q_EMIT stopExecutor();
- RPCUnregisterTimerInterface(rpcTimerInterface);
+ RPCUnsetTimerInterface(rpcTimerInterface);
delete rpcTimerInterface;
delete ui;
}
diff --git a/src/reverselock.h b/src/reverselock.h
index 567636e16a..fac1ccb793 100644
--- a/src/reverselock.h
+++ b/src/reverselock.h
@@ -15,10 +15,12 @@ public:
explicit reverse_lock(Lock& lock) : lock(lock) {
lock.unlock();
+ lock.swap(templock);
}
~reverse_lock() {
- lock.lock();
+ templock.lock();
+ templock.swap(lock);
}
private:
@@ -26,6 +28,7 @@ private:
reverse_lock& operator=(reverse_lock const&);
Lock& lock;
+ Lock templock;
};
#endif // BITCOIN_REVERSELOCK_H
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index bc419d14d9..78d6898bc3 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -33,7 +33,7 @@ static bool fRPCInWarmup = true;
static std::string rpcWarmupStatus("RPC server started");
static CCriticalSection cs_rpcWarmup;
/* Timer-creating functions */
-static std::vector<RPCTimerInterface*> timerInterfaces;
+static RPCTimerInterface* timerInterface = NULL;
/* Map of name to timer.
* @note Can be changed to std::unique_ptr when C++11 */
static std::map<std::string, boost::shared_ptr<RPCTimerBase> > deadlineTimers;
@@ -546,24 +546,28 @@ std::string HelpExampleRpc(const std::string& methodname, const std::string& arg
"\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
}
-void RPCRegisterTimerInterface(RPCTimerInterface *iface)
+void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface)
{
- timerInterfaces.push_back(iface);
+ if (!timerInterface)
+ timerInterface = iface;
}
-void RPCUnregisterTimerInterface(RPCTimerInterface *iface)
+void RPCSetTimerInterface(RPCTimerInterface *iface)
{
- std::vector<RPCTimerInterface*>::iterator i = std::find(timerInterfaces.begin(), timerInterfaces.end(), iface);
- assert(i != timerInterfaces.end());
- timerInterfaces.erase(i);
+ timerInterface = iface;
+}
+
+void RPCUnsetTimerInterface(RPCTimerInterface *iface)
+{
+ if (timerInterface == iface)
+ timerInterface = NULL;
}
void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds)
{
- if (timerInterfaces.empty())
+ if (!timerInterface)
throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC");
deadlineTimers.erase(name);
- RPCTimerInterface* timerInterface = timerInterfaces[0];
LogPrint("rpc", "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name());
deadlineTimers.insert(std::make_pair(name, boost::shared_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000))));
}
diff --git a/src/rpcserver.h b/src/rpcserver.h
index f85ab42f02..9dce318872 100644
--- a/src/rpcserver.h
+++ b/src/rpcserver.h
@@ -100,10 +100,12 @@ public:
virtual RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis) = 0;
};
-/** Register factory function for timers */
-void RPCRegisterTimerInterface(RPCTimerInterface *iface);
-/** Unregister factory function for timers */
-void RPCUnregisterTimerInterface(RPCTimerInterface *iface);
+/** Set the factory function for timers */
+void RPCSetTimerInterface(RPCTimerInterface *iface);
+/** Set the factory function for timer, but only, if unset */
+void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface);
+/** Unset factory function for timers */
+void RPCUnsetTimerInterface(RPCTimerInterface *iface);
/**
* Run func nSeconds from now.
diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp
index e7e627ae0f..8bdff97000 100644
--- a/src/test/reverselock_tests.cpp
+++ b/src/test/reverselock_tests.cpp
@@ -42,22 +42,18 @@ BOOST_AUTO_TEST_CASE(reverselock_errors)
BOOST_CHECK(failed);
BOOST_CHECK(!lock.owns_lock());
- // Make sure trying to lock a lock after it has been reverse locked fails
- failed = false;
- bool locked = false;
+ // Locking the original lock after it has been taken by a reverse lock
+ // makes no sense. Ensure that the original lock no longer owns the lock
+ // after giving it to a reverse one.
lock.lock();
BOOST_CHECK(lock.owns_lock());
-
- try {
+ {
reverse_lock<boost::unique_lock<boost::mutex> > rlock(lock);
- lock.lock();
- locked = true;
- } catch(...) {
- failed = true;
+ BOOST_CHECK(!lock.owns_lock());
}
- BOOST_CHECK(locked && failed);
+ BOOST_CHECK(failed);
BOOST_CHECK(lock.owns_lock());
}
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index f03cb4896c..e84d588026 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -328,7 +328,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
empty_wallet();
}
-BOOST_AUTO_TEST_CASE(pruning_in_ApproximateBestSet)
+BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
{
CoinSet setCoinsRet;
CAmount nValueRet;
@@ -336,15 +336,28 @@ BOOST_AUTO_TEST_CASE(pruning_in_ApproximateBestSet)
LOCK(wallet.cs_wallet);
empty_wallet();
+
+ // Test vValue sort order
+ for (int i = 0; i < 1000; i++)
+ add_coin(1000 * COIN);
+ add_coin(3 * COIN);
+
+ BOOST_CHECK(wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK_EQUAL(nValueRet, 1003 * COIN);
+ BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
+
+ empty_wallet();
+
+ // Test trimming
for (int i = 0; i < 100; i++)
- add_coin(10 * CENT);
+ add_coin(10 * COIN);
for (int i = 0; i < 100; i++)
- add_coin(1000 * CENT);
+ add_coin(1000 * COIN);
- BOOST_CHECK(wallet.SelectCoinsMinConf(100001 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(wallet.SelectCoinsMinConf(100001 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet));
// We need all 100 larger coins and exactly one small coin.
- // Superfluous small coins must be pruned:
- BOOST_CHECK_EQUAL(nValueRet, 100010 * CENT);
+ // Superfluous small coins must be trimmed from the set:
+ BOOST_CHECK_EQUAL(nValueRet, 100010 * COIN);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 101);
}
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 581c688fc7..6b2ebebba7 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -817,6 +817,13 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
}
iter++;
}
+ // If a transaction changes 'conflicted' state, that changes the balance
+ // available of the outputs it spends. So force those to be recomputed
+ BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ {
+ if (mapWallet.count(txin.prevout.hash))
+ mapWallet[txin.prevout.hash].MarkDirty();
+ }
}
}
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index ce57f4dae1..9bbd52f14c 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -61,7 +61,6 @@ static const CAmount nHighTransactionMaxFeeWarning = 100 * nHighTransactionFeeWa
static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
static const bool DEFAULT_WALLETBROADCAST = true;
-class CAccountingEntry;
class CBlockIndex;
class CCoinControl;
class COutput;
@@ -447,6 +446,86 @@ public:
}
};
+/**
+ * Internal transfers.
+ * Database key is acentry<account><counter>.
+ */
+class CAccountingEntry
+{
+public:
+ std::string strAccount;
+ CAmount nCreditDebit;
+ int64_t nTime;
+ std::string strOtherAccount;
+ std::string strComment;
+ mapValue_t mapValue;
+ int64_t nOrderPos; //! position in ordered transaction list
+ uint64_t nEntryNo;
+
+ CAccountingEntry()
+ {
+ SetNull();
+ }
+
+ void SetNull()
+ {
+ nCreditDebit = 0;
+ nTime = 0;
+ strAccount.clear();
+ strOtherAccount.clear();
+ strComment.clear();
+ nOrderPos = -1;
+ nEntryNo = 0;
+ }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ if (!(nType & SER_GETHASH))
+ READWRITE(nVersion);
+ //! Note: strAccount is serialized as part of the key, not here.
+ READWRITE(nCreditDebit);
+ READWRITE(nTime);
+ READWRITE(LIMITED_STRING(strOtherAccount, 65536));
+
+ if (!ser_action.ForRead())
+ {
+ WriteOrderPos(nOrderPos, mapValue);
+
+ if (!(mapValue.empty() && _ssExtra.empty()))
+ {
+ CDataStream ss(nType, nVersion);
+ ss.insert(ss.begin(), '\0');
+ ss << mapValue;
+ ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end());
+ strComment.append(ss.str());
+ }
+ }
+
+ READWRITE(LIMITED_STRING(strComment, 65536));
+
+ size_t nSepPos = strComment.find("\0", 0, 1);
+ if (ser_action.ForRead())
+ {
+ mapValue.clear();
+ if (std::string::npos != nSepPos)
+ {
+ CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion);
+ ss >> mapValue;
+ _ssExtra = std::vector<char>(ss.begin(), ss.end());
+ }
+ ReadOrderPos(nOrderPos, mapValue);
+ }
+ if (std::string::npos != nSepPos)
+ strComment.erase(nSepPos);
+
+ mapValue.erase("n");
+ }
+
+private:
+ std::vector<char> _ssExtra;
+};
/**
@@ -843,87 +922,4 @@ public:
}
};
-
-
-/**
- * Internal transfers.
- * Database key is acentry<account><counter>.
- */
-class CAccountingEntry
-{
-public:
- std::string strAccount;
- CAmount nCreditDebit;
- int64_t nTime;
- std::string strOtherAccount;
- std::string strComment;
- mapValue_t mapValue;
- int64_t nOrderPos; //! position in ordered transaction list
- uint64_t nEntryNo;
-
- CAccountingEntry()
- {
- SetNull();
- }
-
- void SetNull()
- {
- nCreditDebit = 0;
- nTime = 0;
- strAccount.clear();
- strOtherAccount.clear();
- strComment.clear();
- nOrderPos = -1;
- nEntryNo = 0;
- }
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- if (!(nType & SER_GETHASH))
- READWRITE(nVersion);
- //! Note: strAccount is serialized as part of the key, not here.
- READWRITE(nCreditDebit);
- READWRITE(nTime);
- READWRITE(LIMITED_STRING(strOtherAccount, 65536));
-
- if (!ser_action.ForRead())
- {
- WriteOrderPos(nOrderPos, mapValue);
-
- if (!(mapValue.empty() && _ssExtra.empty()))
- {
- CDataStream ss(nType, nVersion);
- ss.insert(ss.begin(), '\0');
- ss << mapValue;
- ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end());
- strComment.append(ss.str());
- }
- }
-
- READWRITE(LIMITED_STRING(strComment, 65536));
-
- size_t nSepPos = strComment.find("\0", 0, 1);
- if (ser_action.ForRead())
- {
- mapValue.clear();
- if (std::string::npos != nSepPos)
- {
- CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion);
- ss >> mapValue;
- _ssExtra = std::vector<char>(ss.begin(), ss.end());
- }
- ReadOrderPos(nOrderPos, mapValue);
- }
- if (std::string::npos != nSepPos)
- strComment.erase(nSepPos);
-
- mapValue.erase("n");
- }
-
-private:
- std::vector<char> _ssExtra;
-};
-
#endif // BITCOIN_WALLET_WALLET_H
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 88dc3102da..5266946ca0 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -15,6 +15,12 @@
#include "utiltime.h"
#include "wallet/wallet.h"
+#if defined(FORCE_BOOST_EMULATED_SCOPED_ENUMS)
+#define BOOST_NO_SCOPED_ENUMS
+#define BOOST_NO_CXX11_SCOPED_ENUMS
+#endif
+
+#include <boost/version.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <boost/scoped_ptr.hpp>
@@ -960,8 +966,13 @@ bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKe
CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);
CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
string strType, strErr;
- bool fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue,
+ bool fReadOK;
+ {
+ // Required in LoadKeyMetadata():
+ LOCK(dummyWallet.cs_wallet);
+ fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue,
wss, strType, strErr);
+ }
if (!IsKeyType(strType))
continue;
if (!fReadOK)