aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/base58.h9
-rw-r--r--src/init.cpp9
-rw-r--r--src/main.cpp14
-rw-r--r--src/net.cpp4
-rw-r--r--src/qt/bitcoin.cpp2
-rw-r--r--src/rpcserver.cpp12
-rw-r--r--src/sync.cpp49
-rw-r--r--src/sync.h8
-rw-r--r--src/test/bip32_tests.cpp11
-rw-r--r--src/test/rpc_tests.cpp23
-rw-r--r--src/test/univalue_tests.cpp6
-rw-r--r--src/univalue/univalue.cpp5
-rw-r--r--src/univalue/univalue.h3
-rw-r--r--src/univalue/univalue_write.cpp7
-rw-r--r--src/util.cpp105
-rw-r--r--src/util.h1
-rw-r--r--src/utilstrencodings.cpp11
-rw-r--r--src/wallet/rpcwallet.cpp1
18 files changed, 203 insertions, 77 deletions
diff --git a/src/base58.h b/src/base58.h
index 787979c827..90014b9496 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -146,7 +146,10 @@ public:
K GetKey() {
K ret;
- ret.Decode(&vchData[0], &vchData[Size]);
+ if (vchData.size() == Size) {
+ //if base58 encouded data not holds a ext key, return a !IsValid() key
+ ret.Decode(&vchData[0]);
+ }
return ret;
}
@@ -154,6 +157,10 @@ public:
SetKey(key);
}
+ CBitcoinExtKeyBase(const std::string& strBase58c) {
+ SetString(strBase58c.c_str(), Params().Base58Prefix(Type).size());
+ }
+
CBitcoinExtKeyBase() {}
};
diff --git a/src/init.cpp b/src/init.cpp
index aba711c3e9..365bd30714 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -673,6 +673,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fLogTimestamps = GetBoolArg("-logtimestamps", true);
fLogIPs = GetBoolArg("-logips", false);
+ LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
+ LogPrintf("Bitcoin version %s (%s)\n", FormatFullVersion(), CLIENT_DATE);
+
// when specifying an explicit binding address, you want to listen on it
// even when -connect or -proxy is specified
if (mapArgs.count("-bind")) {
@@ -946,8 +949,10 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
#endif
if (GetBoolArg("-shrinkdebugfile", !fDebug))
ShrinkDebugFile();
- LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
- LogPrintf("Bitcoin version %s (%s)\n", FormatFullVersion(), CLIENT_DATE);
+
+ if (fPrintToDebugLog)
+ OpenDebugLog();
+
LogPrintf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION));
#ifdef ENABLE_WALLET
LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
diff --git a/src/main.cpp b/src/main.cpp
index cf0002cc35..fefeabeb64 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -83,9 +83,9 @@ struct COrphanTx {
CTransaction tx;
NodeId fromPeer;
};
-map<uint256, COrphanTx> mapOrphanTransactions;
-map<uint256, set<uint256> > mapOrphanTransactionsByPrev;
-void EraseOrphansFor(NodeId peer);
+map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main);;
+map<uint256, set<uint256> > mapOrphanTransactionsByPrev GUARDED_BY(cs_main);;
+void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Returns true if there are nRequired or more blocks of minVersion or above
@@ -535,7 +535,7 @@ CBlockTreeDB *pblocktree = NULL;
// mapOrphanTransactions
//
-bool AddOrphanTx(const CTransaction& tx, NodeId peer)
+bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
uint256 hash = tx.GetHash();
if (mapOrphanTransactions.count(hash))
@@ -565,7 +565,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer)
return true;
}
-void static EraseOrphanTx(uint256 hash)
+void static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash);
if (it == mapOrphanTransactions.end())
@@ -599,7 +599,7 @@ void EraseOrphansFor(NodeId peer)
}
-unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
+unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
unsigned int nEvicted = 0;
while (mapOrphanTransactions.size() > nMaxOrphans)
@@ -3657,7 +3657,7 @@ std::string GetWarnings(const std::string& strFor)
//
-bool static AlreadyHave(const CInv& inv)
+bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
switch (inv.type)
{
diff --git a/src/net.cpp b/src/net.cpp
index e9fd74db45..3cece520de 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -2185,8 +2185,10 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
Fuzz(GetArg("-fuzzmessagestest", 10));
if (ssSend.size() == 0)
+ {
+ LEAVE_CRITICAL_SECTION(cs_vSend);
return;
-
+ }
// Set the size
unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE;
WriteLE32((uint8_t*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize);
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 708d863916..b8aec0c268 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -59,7 +59,9 @@ Q_IMPORT_PLUGIN(qtwcodecs)
Q_IMPORT_PLUGIN(qkrcodecs)
Q_IMPORT_PLUGIN(qtaccessiblewidgets)
#else
+#if QT_VERSION < 0x050400
Q_IMPORT_PLUGIN(AccessibleFactory)
+#endif
#if defined(QT_QPA_PLATFORM_XCB)
Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
#elif defined(QT_QPA_PLATFORM_WINDOWS)
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index bcad06a0c1..03c123a361 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -11,7 +11,6 @@
#include "sync.h"
#include "ui_interface.h"
#include "util.h"
-#include "utilmoneystr.h"
#include "utilstrencodings.h"
#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
@@ -121,8 +120,8 @@ void RPCTypeCheckObj(const UniValue& o,
CAmount AmountFromValue(const UniValue& value)
{
- if (!value.isReal() && !value.isNum())
- throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number");
+ if (!value.isNum() && !value.isStr())
+ throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string");
CAmount amount;
if (!ParseFixedPoint(value.getValStr(), 8, &amount))
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
@@ -133,7 +132,12 @@ CAmount AmountFromValue(const UniValue& value)
UniValue ValueFromAmount(const CAmount& amount)
{
- return UniValue(UniValue::VREAL, FormatMoney(amount));
+ bool sign = amount < 0;
+ int64_t n_abs = (sign ? -amount : amount);
+ int64_t quotient = n_abs / COIN;
+ int64_t remainder = n_abs % COIN;
+ return UniValue(UniValue::VNUM,
+ strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder));
}
uint256 ParseHashV(const UniValue& v, string strName)
diff --git a/src/sync.cpp b/src/sync.cpp
index a422939964..1837e8d53d 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -33,20 +33,22 @@ void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
//
struct CLockLocation {
- CLockLocation(const char* pszName, const char* pszFile, int nLine)
+ CLockLocation(const char* pszName, const char* pszFile, int nLine, bool fTryIn)
{
mutexName = pszName;
sourceFile = pszFile;
sourceLine = nLine;
+ fTry = fTryIn;
}
std::string ToString() const
{
- return mutexName + " " + sourceFile + ":" + itostr(sourceLine);
+ return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : "");
}
std::string MutexName() const { return mutexName; }
+ bool fTry;
private:
std::string mutexName;
std::string sourceFile;
@@ -62,23 +64,52 @@ static boost::thread_specific_ptr<LockStack> lockstack;
static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{
+ // We attempt to not assert on probably-not deadlocks by assuming that
+ // a try lock will immediately have otherwise bailed if it had
+ // failed to get the lock
+ // We do this by, for the locks which triggered the potential deadlock,
+ // in either lockorder, checking that the second of the two which is locked
+ // is only a TRY_LOCK, ignoring locks if they are reentrant.
+ bool firstLocked = false;
+ bool secondLocked = false;
+ bool onlyMaybeDeadlock = false;
+
LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
LogPrintf("Previous lock order was:\n");
BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s2) {
- if (i.first == mismatch.first)
+ if (i.first == mismatch.first) {
LogPrintf(" (1)");
- if (i.first == mismatch.second)
+ if (!firstLocked && secondLocked && i.second.fTry)
+ onlyMaybeDeadlock = true;
+ firstLocked = true;
+ }
+ if (i.first == mismatch.second) {
LogPrintf(" (2)");
+ if (!secondLocked && firstLocked && i.second.fTry)
+ onlyMaybeDeadlock = true;
+ secondLocked = true;
+ }
LogPrintf(" %s\n", i.second.ToString());
}
+ firstLocked = false;
+ secondLocked = false;
LogPrintf("Current lock order is:\n");
BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s1) {
- if (i.first == mismatch.first)
+ if (i.first == mismatch.first) {
LogPrintf(" (1)");
- if (i.first == mismatch.second)
+ if (!firstLocked && secondLocked && i.second.fTry)
+ onlyMaybeDeadlock = true;
+ firstLocked = true;
+ }
+ if (i.first == mismatch.second) {
LogPrintf(" (2)");
+ if (!secondLocked && firstLocked && i.second.fTry)
+ onlyMaybeDeadlock = true;
+ secondLocked = true;
+ }
LogPrintf(" %s\n", i.second.ToString());
}
+ assert(onlyMaybeDeadlock);
}
static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
@@ -101,10 +132,8 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
lockorders[p1] = (*lockstack);
std::pair<void*, void*> p2 = std::make_pair(c, i.first);
- if (lockorders.count(p2)) {
+ if (lockorders.count(p2))
potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]);
- break;
- }
}
}
dd_mutex.unlock();
@@ -119,7 +148,7 @@ static void pop_lock()
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
{
- push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry);
+ push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry);
}
void LeaveCritical()
diff --git a/src/sync.h b/src/sync.h
index 78b9043477..705647e4a5 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -101,7 +101,7 @@ void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
/** Wrapper around boost::unique_lock<Mutex> */
template <typename Mutex>
-class CMutexLock
+class SCOPED_LOCKABLE CMutexLock
{
private:
boost::unique_lock<Mutex> lock;
@@ -129,7 +129,7 @@ private:
}
public:
- CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock)
+ CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, boost::defer_lock)
{
if (fTry)
TryEnter(pszName, pszFile, nLine);
@@ -137,7 +137,7 @@ public:
Enter(pszName, pszFile, nLine);
}
- CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false)
+ CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
{
if (!pmutexIn) return;
@@ -148,7 +148,7 @@ public:
Enter(pszName, pszFile, nLine);
}
- ~CMutexLock()
+ ~CMutexLock() UNLOCK_FUNCTION()
{
if (lock.owns_lock())
LeaveCritical();
diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp
index 0d815c27fd..69084213a2 100644
--- a/src/test/bip32_tests.cpp
+++ b/src/test/bip32_tests.cpp
@@ -88,12 +88,23 @@ void RunTest(const TestVector &test) {
unsigned char data[74];
key.Encode(data);
pubkey.Encode(data);
+
// Test private key
CBitcoinExtKey b58key; b58key.SetKey(key);
BOOST_CHECK(b58key.ToString() == derive.prv);
+
+ CBitcoinExtKey b58keyDecodeCheck(derive.prv);
+ CExtKey checkKey = b58keyDecodeCheck.GetKey();
+ assert(checkKey == key); //ensure a base58 decoded key also matches
+
// Test public key
CBitcoinExtPubKey b58pubkey; b58pubkey.SetKey(pubkey);
BOOST_CHECK(b58pubkey.ToString() == derive.pub);
+
+ CBitcoinExtPubKey b58PubkeyDecodeCheck(derive.pub);
+ CExtPubKey checkPubKey = b58PubkeyDecodeCheck.GetKey();
+ assert(checkPubKey == pubkey); //ensure a base58 decoded pubkey also matches
+
// Derive new keys
CExtKey keyNew;
BOOST_CHECK(key.Derive(keyNew, derive.nChild));
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 25599beafc..7946b02855 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -120,6 +120,29 @@ BOOST_AUTO_TEST_CASE(rpc_format_monetary_values)
BOOST_CHECK(ValueFromAmount(100000000LL).write() == "1.00000000");
BOOST_CHECK(ValueFromAmount(2099999999999990LL).write() == "20999999.99999990");
BOOST_CHECK(ValueFromAmount(2099999999999999LL).write() == "20999999.99999999");
+
+ BOOST_CHECK_EQUAL(ValueFromAmount(0).write(), "0.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount((COIN/10000)*123456789).write(), "12345.67890000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(-COIN).write(), "-1.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(-COIN/10).write(), "-0.10000000");
+
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000000).write(), "100000000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000000).write(), "10000000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000000).write(), "1000000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000).write(), "100000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000).write(), "10000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000).write(), "1000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100).write(), "100.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10).write(), "10.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN).write(), "1.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10).write(), "0.10000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100).write(), "0.01000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000).write(), "0.00100000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000).write(), "0.00010000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000).write(), "0.00001000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000000).write(), "0.00000100");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000000).write(), "0.00000010");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000000).write(), "0.00000001");
}
static UniValue ValueFromString(const std::string &str)
diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp
index 16bc8d30f6..67cb9b9623 100644
--- a/src/test/univalue_tests.cpp
+++ b/src/test/univalue_tests.cpp
@@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(univalue_constructor)
double vd = -7.21;
UniValue v7(vd);
- BOOST_CHECK(v7.isReal());
+ BOOST_CHECK(v7.isNum());
BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21");
string vs("yawn");
@@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(univalue_set)
BOOST_CHECK_EQUAL(v.getValStr(), "zum");
BOOST_CHECK(v.setFloat(-1.01));
- BOOST_CHECK(v.isReal());
+ BOOST_CHECK(v.isNum());
BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
BOOST_CHECK(v.setInt((int)1023));
@@ -272,7 +272,7 @@ BOOST_AUTO_TEST_CASE(univalue_object)
objTypes["distance"] = UniValue::VNUM;
objTypes["time"] = UniValue::VNUM;
objTypes["calories"] = UniValue::VNUM;
- objTypes["temperature"] = UniValue::VREAL;
+ objTypes["temperature"] = UniValue::VNUM;
objTypes["cat1"] = UniValue::VNUM;
objTypes["cat2"] = UniValue::VNUM;
BOOST_CHECK(obj.checkObject(objTypes));
diff --git a/src/univalue/univalue.cpp b/src/univalue/univalue.cpp
index 6920c44c96..1d49a2cfc9 100644
--- a/src/univalue/univalue.cpp
+++ b/src/univalue/univalue.cpp
@@ -86,7 +86,7 @@ bool UniValue::setFloat(double val)
oss << std::setprecision(16) << val;
bool ret = setNumStr(oss.str());
- typ = VREAL;
+ typ = VNUM;
return ret;
}
@@ -210,7 +210,6 @@ const char *uvTypeName(UniValue::VType t)
case UniValue::VARR: return "array";
case UniValue::VSTR: return "string";
case UniValue::VNUM: return "number";
- case UniValue::VREAL: return "number";
}
// not reached
@@ -280,7 +279,7 @@ int64_t UniValue::get_int64() const
double UniValue::get_real() const
{
- if (typ != VREAL && typ != VNUM)
+ if (typ != VNUM)
throw std::runtime_error("JSON value is not a number as expected");
double retval;
if (!ParseDouble(getValStr(), &retval))
diff --git a/src/univalue/univalue.h b/src/univalue/univalue.h
index 54239741e2..4742b56f3d 100644
--- a/src/univalue/univalue.h
+++ b/src/univalue/univalue.h
@@ -16,7 +16,7 @@
class UniValue {
public:
- enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VREAL, VBOOL, };
+ enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
UniValue() { typ = VNULL; }
UniValue(UniValue::VType initialType, const std::string& initialStr = "") {
@@ -78,7 +78,6 @@ public:
bool isBool() const { return (typ == VBOOL); }
bool isStr() const { return (typ == VSTR); }
bool isNum() const { return (typ == VNUM); }
- bool isReal() const { return (typ == VREAL); }
bool isArray() const { return (typ == VARR); }
bool isObject() const { return (typ == VOBJ); }
diff --git a/src/univalue/univalue_write.cpp b/src/univalue/univalue_write.cpp
index d360c253b0..bce3997af7 100644
--- a/src/univalue/univalue_write.cpp
+++ b/src/univalue/univalue_write.cpp
@@ -61,13 +61,6 @@ string UniValue::write(unsigned int prettyIndent,
case VSTR:
s += "\"" + json_escape(val) + "\"";
break;
- case VREAL:
- {
- std::stringstream ss;
- ss << std::showpoint << std::fixed << std::setprecision(8) << get_real();
- s += ss.str();
- }
- break;
case VNUM:
s += val;
break;
diff --git a/src/util.cpp b/src/util.cpp
index 00d0f3a00d..37d52037c0 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -114,7 +114,7 @@ CTranslationInterface translationInterface;
/** Init OpenSSL library multithreading support */
static CCriticalSection** ppmutexOpenSSL;
-void locking_callback(int mode, int i, const char* file, int line)
+void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
{
if (mode & CRYPTO_LOCK) {
ENTER_CRITICAL_SECTION(*ppmutexOpenSSL[i]);
@@ -175,23 +175,51 @@ instance_of_cinit;
*/
static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT;
+
/**
- * We use boost::call_once() to make sure these are initialized
- * in a thread-safe manner the first time called:
+ * We use boost::call_once() to make sure mutexDebugLog and
+ * vMsgsBeforeOpenLog are initialized in a thread-safe manner.
+ *
+ * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog
+ * are leaked on exit. This is ugly, but will be cleaned up by
+ * the OS/libc. When the shutdown sequence is fully audited and
+ * tested, explicit destruction of these objects can be implemented.
*/
static FILE* fileout = NULL;
static boost::mutex* mutexDebugLog = NULL;
+static list<string> *vMsgsBeforeOpenLog;
+
+static int FileWriteStr(const std::string &str, FILE *fp)
+{
+ return fwrite(str.data(), 1, str.size(), fp);
+}
static void DebugPrintInit()
{
- assert(fileout == NULL);
assert(mutexDebugLog == NULL);
+ mutexDebugLog = new boost::mutex();
+ vMsgsBeforeOpenLog = new list<string>;
+}
+
+void OpenDebugLog()
+{
+ boost::call_once(&DebugPrintInit, debugPrintInitFlag);
+ boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
+ assert(fileout == NULL);
+ assert(vMsgsBeforeOpenLog);
boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
fileout = fopen(pathDebug.string().c_str(), "a");
if (fileout) setbuf(fileout, NULL); // unbuffered
- mutexDebugLog = new boost::mutex();
+ // dump buffered messages from before we opened the log
+ while (!vMsgsBeforeOpenLog->empty()) {
+ FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
+ vMsgsBeforeOpenLog->pop_front();
+ }
+
+ delete vMsgsBeforeOpenLog;
+ vMsgsBeforeOpenLog = NULL;
}
bool LogAcceptCategory(const char* category)
@@ -223,44 +251,67 @@ bool LogAcceptCategory(const char* category)
return true;
}
+/**
+ * fStartedNewLine is a state variable held by the calling context that will
+ * suppress printing of the timestamp when multiple calls are made that don't
+ * end in a newline. Initialize it to true, and hold it, in the calling context.
+ */
+static std::string LogTimestampStr(const std::string &str, bool *fStartedNewLine)
+{
+ string strStamped;
+
+ if (!fLogTimestamps)
+ return str;
+
+ if (*fStartedNewLine)
+ strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()) + ' ' + str;
+ else
+ strStamped = str;
+
+ if (!str.empty() && str[str.size()-1] == '\n')
+ *fStartedNewLine = true;
+ else
+ *fStartedNewLine = false;
+
+ return strStamped;
+}
+
int LogPrintStr(const std::string &str)
{
int ret = 0; // Returns total number of characters written
+ static bool fStartedNewLine = true;
if (fPrintToConsole)
{
// print to console
ret = fwrite(str.data(), 1, str.size(), stdout);
fflush(stdout);
}
- else if (fPrintToDebugLog && AreBaseParamsConfigured())
+ else if (fPrintToDebugLog)
{
- static bool fStartedNewLine = true;
boost::call_once(&DebugPrintInit, debugPrintInitFlag);
-
- if (fileout == NULL)
- return ret;
-
boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
- // reopen the log file, if requested
- if (fReopenDebugLog) {
- fReopenDebugLog = false;
- boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
- if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL)
- setbuf(fileout, NULL); // unbuffered
- }
+ string strTimestamped = LogTimestampStr(str, &fStartedNewLine);
- // Debug print useful for profiling
- if (fLogTimestamps && fStartedNewLine)
- ret += fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str());
- if (!str.empty() && str[str.size()-1] == '\n')
- fStartedNewLine = true;
+ // buffer if we haven't opened the log yet
+ if (fileout == NULL) {
+ assert(vMsgsBeforeOpenLog);
+ ret = strTimestamped.length();
+ vMsgsBeforeOpenLog->push_back(strTimestamped);
+ }
else
- fStartedNewLine = false;
-
- ret = fwrite(str.data(), 1, str.size(), fileout);
+ {
+ // reopen the log file, if requested
+ if (fReopenDebugLog) {
+ fReopenDebugLog = false;
+ boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
+ if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL)
+ setbuf(fileout, NULL); // unbuffered
+ }
+
+ ret = FileWriteStr(strTimestamped, fileout);
+ }
}
-
return ret;
}
diff --git a/src/util.h b/src/util.h
index 6019e25015..afc9a378bb 100644
--- a/src/util.h
+++ b/src/util.h
@@ -125,6 +125,7 @@ void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map
boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
boost::filesystem::path GetTempPath();
+void OpenDebugLog();
void ShrinkDebugFile();
void runCommand(const std::string& strCommand);
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp
index 7208ca9474..1f7a2cae2c 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -464,11 +464,12 @@ bool ParseDouble(const std::string& str, double *out)
return false;
if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
return false;
- char *endp = NULL;
- errno = 0; // strtod will not set errno if valid
- double n = strtod(str.c_str(), &endp);
- if(out) *out = n;
- return endp && *endp == 0 && !errno;
+ std::istringstream text(str);
+ text.imbue(std::locale::classic());
+ double result;
+ text >> result;
+ if(out) *out = result;
+ return text.eof() && !text.fail();
}
std::string FormatParagraph(const std::string& in, size_t width, size_t indent)
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 101fb53762..342ce13af1 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -477,7 +477,6 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp)
addressInfo.push_back(CBitcoinAddress(address).ToString());
addressInfo.push_back(ValueFromAmount(balances[address]));
{
- LOCK(pwalletMain->cs_wallet);
if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
}