aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am38
-rw-r--r--src/Makefile.qt.include6
-rw-r--r--src/Makefile.qttest.include4
-rw-r--r--src/Makefile.test.include19
-rw-r--r--src/addrman.cpp14
-rw-r--r--src/alert.cpp6
-rw-r--r--src/alert.h7
-rw-r--r--src/bitcoin-cli.cpp2
-rw-r--r--src/bitcoin-tx.cpp41
-rw-r--r--src/bitcoind.cpp1
-rw-r--r--src/coins.cpp60
-rw-r--r--src/coins.h51
-rw-r--r--src/compat.h25
-rw-r--r--src/core.cpp40
-rw-r--r--src/core.h9
-rw-r--r--src/core_write.cpp1
-rw-r--r--src/crypter.cpp30
-rw-r--r--src/crypter.h5
-rw-r--r--src/db.cpp2
-rw-r--r--src/db.h1
-rw-r--r--src/init.cpp7
-rw-r--r--src/keystore.cpp1
-rw-r--r--src/keystore.h9
-rw-r--r--src/leveldbwrapper.h4
-rw-r--r--src/m4/ax_boost_base.m46
-rw-r--r--src/m4/bitcoin_qt.m414
-rw-r--r--src/main.cpp189
-rw-r--r--src/main.h82
-rw-r--r--src/miner.cpp31
-rw-r--r--src/net.cpp188
-rw-r--r--src/net.h162
-rw-r--r--src/netbase.cpp24
-rw-r--r--src/netbase.h5
-rw-r--r--src/noui.cpp1
-rw-r--r--src/pow.cpp1
-rw-r--r--src/protocol.cpp6
-rw-r--r--src/protocol.h4
-rw-r--r--src/qt/bitcoin.cpp5
-rw-r--r--src/qt/bitcoin.qrc2
-rw-r--r--src/qt/bitcoingui.cpp48
-rw-r--r--src/qt/bitcoingui.h2
-rw-r--r--src/qt/clientmodel.cpp1
-rw-r--r--src/qt/forms/overviewpage.ui6
-rw-r--r--src/qt/guiutil.cpp15
-rw-r--r--src/qt/guiutil.h9
-rw-r--r--src/qt/optionsdialog.cpp1
-rw-r--r--src/qt/paymentserver.cpp1
-rw-r--r--src/qt/res/icons/toolbar.pngbin815 -> 0 bytes
-rw-r--r--src/qt/res/icons/toolbar_testnet.pngbin678 -> 0 bytes
-rw-r--r--src/qt/transactiondesc.cpp1
-rw-r--r--src/qt/utilitydialog.cpp5
-rw-r--r--src/qt/walletmodel.cpp20
-rw-r--r--src/qt/walletmodel.h5
-rw-r--r--src/random.cpp4
-rw-r--r--src/rpcblockchain.cpp25
-rw-r--r--src/rpcdump.cpp2
-rw-r--r--src/rpcmining.cpp1
-rw-r--r--src/rpcnet.cpp33
-rw-r--r--src/rpcprotocol.cpp4
-rw-r--r--src/rpcrawtransaction.cpp4
-rw-r--r--src/rpcserver.cpp12
-rw-r--r--src/rpcserver.h1
-rw-r--r--src/script.cpp17
-rw-r--r--src/script.h9
-rw-r--r--src/serialize.h112
-rw-r--r--src/test/DoS_tests.cpp1
-rw-r--r--src/test/alert_tests.cpp3
-rw-r--r--src/test/allocator_tests.cpp2
-rw-r--r--src/test/base32_tests.cpp2
-rw-r--r--src/test/base64_tests.cpp2
-rw-r--r--src/test/bctest.py53
-rwxr-xr-xsrc/test/bitcoin-util-test.py12
-rw-r--r--src/test/checkblock_tests.cpp1
-rw-r--r--src/test/crypto_tests.cpp2
-rw-r--r--src/test/data/bitcoin-util-test.json38
-rw-r--r--src/test/data/blanktx.hex1
-rw-r--r--src/test/data/tt-delin1-out.hex1
-rw-r--r--src/test/data/tt-delout1-out.hex1
-rw-r--r--src/test/data/tt-locktime317000-out.hex1
-rw-r--r--src/test/data/tx394b54bb.hex1
-rw-r--r--src/test/data/txcreate1.hex1
-rw-r--r--src/test/hash_tests.cpp2
-rw-r--r--src/test/rpc_tests.cpp32
-rw-r--r--src/test/script_tests.cpp11
-rw-r--r--src/test/test_bitcoin.cpp1
-rw-r--r--src/test/timedata_tests.cpp38
-rw-r--r--src/test/univalue_tests.cpp275
-rw-r--r--src/test/util_tests.cpp28
-rw-r--r--src/timedata.cpp6
-rw-r--r--src/timedata.h59
-rw-r--r--src/tinyformat.h3
-rw-r--r--src/txdb.cpp25
-rw-r--r--src/txdb.h10
-rw-r--r--src/txmempool.cpp18
-rw-r--r--src/txmempool.h12
-rw-r--r--src/uint256.cpp3
-rw-r--r--src/univalue/gen.cpp78
-rw-r--r--src/univalue/univalue.cpp2
-rw-r--r--src/univalue/univalue_escapes.h262
-rw-r--r--src/univalue/univalue_write.cpp32
-rw-r--r--src/util.cpp596
-rw-r--r--src/util.h301
-rw-r--r--src/utilmoneystr.cpp75
-rw-r--r--src/utilmoneystr.h19
-rw-r--r--src/utilstrencodings.cpp496
-rw-r--r--src/utilstrencodings.h97
-rw-r--r--src/utiltime.cpp66
-rw-r--r--src/utiltime.h20
-rw-r--r--src/version.cpp28
-rw-r--r--src/version.h6
-rw-r--r--src/wallet.cpp25
-rw-r--r--src/wallet.h35
-rw-r--r--src/walletdb.cpp3
113 files changed, 2633 insertions, 1594 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 727a88c3e7..655bfc88c3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,3 @@
-AM_CPPFLAGS = $(INCLUDES)
AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS)
if USE_LIBSECP256K1
@@ -22,7 +21,7 @@ $(LIBLEVELDB) $(LIBMEMENV):
endif
BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config
-BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS)
+BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS)
if USE_LIBSECP256K1
BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include
@@ -56,12 +55,10 @@ if BUILD_BITCOIND
bin_PROGRAMS += bitcoind
endif
-if BUILD_BITCOIN_CLI
- bin_PROGRAMS += bitcoin-cli
+if BUILD_BITCOIN_UTILS
+ bin_PROGRAMS += bitcoin-cli bitcoin-tx
endif
-bin_PROGRAMS += bitcoin-tx
-
.PHONY: FORCE
# bitcoin core #
BITCOIN_CORE_H = \
@@ -112,6 +109,9 @@ BITCOIN_CORE_H = \
ui_interface.h \
uint256.h \
util.h \
+ utilstrencodings.h \
+ utilmoneystr.h \
+ utiltime.h \
version.h \
walletdb.h \
wallet.h \
@@ -188,6 +188,7 @@ univalue_libbitcoin_univalue_a_SOURCES = \
univalue/univalue.cpp \
univalue/univalue_read.cpp \
univalue/univalue_write.cpp \
+ univalue/univalue_escapes.h \
univalue/univalue.h
# common: shared between bitcoind, and bitcoin-qt and non-server tools
@@ -221,6 +222,9 @@ libbitcoin_util_a_SOURCES = \
sync.cpp \
uint256.cpp \
util.cpp \
+ utilstrencodings.cpp \
+ utilmoneystr.cpp \
+ utiltime.cpp \
version.cpp \
$(BITCOIN_CORE_H)
@@ -230,6 +234,7 @@ libbitcoin_util_a_SOURCES += compat/glibcxx_compat.cpp
endif
# cli: shared between bitcoin-cli and bitcoin-qt
+libbitcoin_cli_a_CPPFLAGS = $(BITCOIN_INCLUDES)
libbitcoin_cli_a_SOURCES = \
rpcclient.cpp \
$(BITCOIN_CORE_H)
@@ -261,8 +266,9 @@ if TARGET_WINDOWS
bitcoind_SOURCES += bitcoind-res.rc
endif
-bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS)
+bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS)
bitcoind_CPPFLAGS = $(BITCOIN_INCLUDES)
+bitcoind_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS)
# bitcoin-cli binary #
bitcoin_cli_LDADD = \
@@ -270,7 +276,10 @@ bitcoin_cli_LDADD = \
$(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
- $(BOOST_LIBS)
+ $(BOOST_LIBS) \
+ $(SSL_LIBS) \
+ $(CRYPTO_LIBS)
+
bitcoin_cli_SOURCES = \
bitcoin-cli.cpp
@@ -285,15 +294,24 @@ bitcoin_tx_LDADD = \
$(LIBBITCOIN_UNIVALUE) \
$(LIBBITCOIN_COMMON) \
$(LIBBITCOIN_UTIL) \
- $(LIBBITCOIN_CRYPTO) \
- $(BOOST_LIBS)
+ $(LIBBITCOIN_CRYPTO)
+
+if USE_LIBSECP256K1
+ bitcoin_tx_LDADD += secp256k1/libsecp256k1.la
+endif
+
+ bitcoin_tx_LDADD += $(BOOST_LIBS) \
+ $(SSL_LIBS) \
+ $(CRYPTO_LIBS)
bitcoin_tx_SOURCES = bitcoin-tx.cpp
bitcoin_tx_CPPFLAGS = $(BITCOIN_INCLUDES)
#
+bitcoin_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS)
if TARGET_WINDOWS
bitcoin_cli_SOURCES += bitcoin-cli-res.rc
endif
+bitcoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS)
CLEANFILES = leveldb/libleveldb.a leveldb/libmemenv.a *.gcda *.gcno
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index eef0c317c6..1ea039adb3 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -248,8 +248,6 @@ RES_ICONS = \
qt/res/icons/remove.png \
qt/res/icons/send.png \
qt/res/icons/synced.png \
- qt/res/icons/toolbar.png \
- qt/res/icons/toolbar_testnet.png \
qt/res/icons/transaction0.png \
qt/res/icons/transaction2.png \
qt/res/icons/transaction_conflicted.png \
@@ -363,11 +361,11 @@ if ENABLE_WALLET
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
endif
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
- $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS)
+ $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS)
if USE_LIBSECP256K1
qt_bitcoin_qt_LDADD += secp256k1/libsecp256k1.la
endif
-qt_bitcoin_qt_LDFLAGS = $(AM_LDFLAGS) $(QT_LDFLAGS)
+qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS)
#locale/foo.ts -> locale/foo.qm
QT_QM=$(QT_TS:.ts=.qm)
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index d49b2240ea..2cba5b7e1e 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -32,11 +32,11 @@ qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
endif
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) \
$(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
- $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS)
+ $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS)
if USE_LIBSECP256K1
qt_test_test_bitcoin_qt_LDADD += secp256k1/libsecp256k1.la
endif
-qt_test_test_bitcoin_qt_LDFLAGS = $(AM_LDFLAGS) $(QT_LDFLAGS)
+qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS)
CLEAN_BITCOIN_QT_TEST = $(TEST_QT_MOC_CPP) qt/test/*.gcda qt/test/*.gcno
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 72451fba9a..b4360831bb 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -1,8 +1,20 @@
-TESTS += test/test_bitcoin
+TESTS += test/test_bitcoin test/bitcoin-util-test.py
bin_PROGRAMS += test/test_bitcoin
TEST_SRCDIR = test
TEST_BINARY=test/test_bitcoin$(EXEEXT)
+
+EXTRA_DIST += \
+ test/bctest.py \
+ test/bitcoin-util-test.py \
+ test/data/bitcoin-util-test.json \
+ test/data/blanktx.hex \
+ test/data/tt-delin1-out.hex \
+ test/data/tt-delout1-out.hex \
+ test/data/tt-locktime317000-out.hex \
+ test/data/tx394b54bb.hex \
+ test/data/txcreate1.hex
+
JSON_TEST_FILES = \
test/data/script_valid.json \
test/data/base58_keys_valid.json \
@@ -49,8 +61,10 @@ BITCOIN_TESTS =\
test/sigopcount_tests.cpp \
test/skiplist_tests.cpp \
test/test_bitcoin.cpp \
+ test/timedata_tests.cpp \
test/transaction_tests.cpp \
test/uint256_tests.cpp \
+ test/univalue_tests.cpp \
test/util_tests.cpp \
test/scriptnum_tests.cpp \
test/sighash_tests.cpp
@@ -74,7 +88,8 @@ if USE_LIBSECP256K1
test_test_bitcoin_LDADD += secp256k1/libsecp256k1.la
endif
-test_test_bitcoin_LDADD += $(BDB_LIBS)
+test_test_bitcoin_LDADD += $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS)
+test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS)
nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
diff --git a/src/addrman.cpp b/src/addrman.cpp
index 3628af2eab..704766dbf8 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -492,17 +492,23 @@ int CAddrMan::Check_()
void CAddrMan::GetAddr_(std::vector<CAddress> &vAddr)
{
- int nNodes = ADDRMAN_GETADDR_MAX_PCT*vRandom.size()/100;
+ unsigned int nNodes = ADDRMAN_GETADDR_MAX_PCT * vRandom.size() / 100;
if (nNodes > ADDRMAN_GETADDR_MAX)
nNodes = ADDRMAN_GETADDR_MAX;
- // perform a random shuffle over the first nNodes elements of vRandom (selecting from all)
- for (int n = 0; n<nNodes; n++)
+ // gather a list of random nodes, skipping those of low quality
+ for (unsigned int n = 0; n < vRandom.size(); n++)
{
+ if (vAddr.size() >= nNodes)
+ break;
+
int nRndPos = GetRandInt(vRandom.size() - n) + n;
SwapRandom(n, nRndPos);
assert(mapInfo.count(vRandom[n]) == 1);
- vAddr.push_back(mapInfo[vRandom[n]]);
+
+ const CAddrInfo& ai = mapInfo[vRandom[n]];
+ if (!ai.IsTerrible())
+ vAddr.push_back(ai);
}
}
diff --git a/src/alert.cpp b/src/alert.cpp
index 258a2b52c4..3271ecfbfd 100644
--- a/src/alert.cpp
+++ b/src/alert.cpp
@@ -19,6 +19,7 @@
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/foreach.hpp>
+#include <boost/thread.hpp>
using namespace std;
@@ -80,11 +81,6 @@ std::string CUnsignedAlert::ToString() const
strStatusBar);
}
-void CUnsignedAlert::print() const
-{
- LogPrintf("%s", ToString());
-}
-
void CAlert::SetNull()
{
CUnsignedAlert::SetNull();
diff --git a/src/alert.h b/src/alert.h
index da140be5e5..b9d850b565 100644
--- a/src/alert.h
+++ b/src/alert.h
@@ -60,15 +60,14 @@ public:
READWRITE(setSubVer);
READWRITE(nPriority);
- READWRITE(strComment);
- READWRITE(strStatusBar);
- READWRITE(strReserved);
+ READWRITE(LIMITED_STRING(strComment, 65536));
+ READWRITE(LIMITED_STRING(strStatusBar, 256));
+ READWRITE(LIMITED_STRING(strReserved, 256));
)
void SetNull();
std::string ToString() const;
- void print() const;
};
/** An alert is a combination of a serialized CUnsignedAlert and a signature. */
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 0609adcab3..871aaf93df 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -8,6 +8,8 @@
#include "rpcclient.h"
#include "rpcprotocol.h"
#include "chainparamsbase.h"
+#include "utilstrencodings.h"
+#include "version.h"
#include <boost/filesystem/operations.hpp>
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index 299315424b..75f0fb69f2 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -4,6 +4,7 @@
#include "base58.h"
#include "util.h"
+#include "utilmoneystr.h"
#include "core.h"
#include "main.h" // for MAX_BLOCK_SIZE
#include "keystore.h"
@@ -13,6 +14,7 @@
#include <stdio.h>
#include <boost/assign/list_of.hpp>
+#include <boost/algorithm/string.hpp>
using namespace std;
using namespace boost::assign;
@@ -283,12 +285,12 @@ static const struct {
const char *flagStr;
int flags;
} sighashOptions[N_SIGHASH_OPTS] = {
- "ALL", SIGHASH_ALL,
- "NONE", SIGHASH_NONE,
- "SINGLE", SIGHASH_SINGLE,
- "ALL|ANYONECANPAY", SIGHASH_ALL|SIGHASH_ANYONECANPAY,
- "NONE|ANYONECANPAY", SIGHASH_NONE|SIGHASH_ANYONECANPAY,
- "SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY,
+ {"ALL", SIGHASH_ALL},
+ {"NONE", SIGHASH_NONE},
+ {"SINGLE", SIGHASH_SINGLE},
+ {"ALL|ANYONECANPAY", SIGHASH_ALL|SIGHASH_ANYONECANPAY},
+ {"NONE|ANYONECANPAY", SIGHASH_NONE|SIGHASH_ANYONECANPAY},
+ {"SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY},
};
static bool findSighashFlags(int& flags, const string& flagStr)
@@ -501,13 +503,34 @@ static void OutputTx(const CTransaction& tx)
OutputTxHex(tx);
}
+static string readStdin()
+{
+ char buf[4096];
+ string ret;
+
+ while (!feof(stdin)) {
+ size_t bread = fread(buf, 1, sizeof(buf), stdin);
+ ret.append(buf, bread);
+ if (bread < sizeof(buf))
+ break;
+ }
+
+ if (ferror(stdin))
+ throw runtime_error("error reading stdin");
+
+ boost::algorithm::trim_right(ret);
+
+ return ret;
+}
+
static int CommandLineRawTx(int argc, char* argv[])
{
string strPrint;
int nRet = 0;
try {
- // Skip switches
- while (argc > 1 && IsSwitchChar(argv[1][0])) {
+ // Skip switches; Permit common stdin convention "-"
+ while (argc > 1 && IsSwitchChar(argv[1][0]) &&
+ (argv[1][1] != 0)) {
argc--;
argv++;
}
@@ -522,6 +545,8 @@ static int CommandLineRawTx(int argc, char* argv[])
// param: hex-encoded bitcoin transaction
string strHexTx(argv[1]);
+ if (strHexTx == "-") // "-" implies standard input
+ strHexTx = readStdin();
if (!DecodeHexTx(txDecodeTmp, strHexTx))
throw runtime_error("invalid transaction encoding");
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index 880955481b..5be8708979 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -12,6 +12,7 @@
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
+#include <boost/thread.hpp>
/* Introduction text for doxygen: */
diff --git a/src/coins.cpp b/src/coins.cpp
index fe40911db7..7bfb84ef3e 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -52,30 +52,30 @@ bool CCoins::Spend(int nPos) {
}
-bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) { return false; }
+bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; }
bool CCoinsView::SetCoins(const uint256 &txid, const CCoins &coins) { return false; }
-bool CCoinsView::HaveCoins(const uint256 &txid) { return false; }
-uint256 CCoinsView::GetBestBlock() { return uint256(0); }
+bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; }
+uint256 CCoinsView::GetBestBlock() const { return uint256(0); }
bool CCoinsView::SetBestBlock(const uint256 &hashBlock) { return false; }
-bool CCoinsView::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
-bool CCoinsView::GetStats(CCoinsStats &stats) { return false; }
+bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; }
+bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; }
CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { }
-bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) { return base->GetCoins(txid, coins); }
+bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); }
bool CCoinsViewBacked::SetCoins(const uint256 &txid, const CCoins &coins) { return base->SetCoins(txid, coins); }
-bool CCoinsViewBacked::HaveCoins(const uint256 &txid) { return base->HaveCoins(txid); }
-uint256 CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); }
+bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); }
+uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); }
bool CCoinsViewBacked::SetBestBlock(const uint256 &hashBlock) { return base->SetBestBlock(hashBlock); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; }
-bool CCoinsViewBacked::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
-bool CCoinsViewBacked::GetStats(CCoinsStats &stats) { return base->GetStats(stats); }
+bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); }
+bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); }
CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), hashBlock(0) { }
-bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) {
+bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const {
if (cacheCoins.count(txid)) {
coins = cacheCoins[txid];
return true;
@@ -99,19 +99,29 @@ CCoinsMap::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) {
return ret;
}
+CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const {
+ /* Avoid redundant implementation with the const-cast. */
+ return const_cast<CCoinsViewCache*>(this)->FetchCoins(txid);
+}
+
CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) {
CCoinsMap::iterator it = FetchCoins(txid);
assert(it != cacheCoins.end());
return it->second;
}
+const CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) const {
+ /* Avoid redundant implementation with the const-cast. */
+ return const_cast<CCoinsViewCache*>(this)->GetCoins(txid);
+}
+
bool CCoinsViewCache::SetCoins(const uint256 &txid, const CCoins &coins) {
cacheCoins[txid] = coins;
return true;
}
-bool CCoinsViewCache::HaveCoins(const uint256 &txid) {
- CCoinsMap::iterator it = FetchCoins(txid);
+bool CCoinsViewCache::HaveCoins(const uint256 &txid) const {
+ CCoinsMap::const_iterator it = FetchCoins(txid);
// We're using vtx.empty() instead of IsPruned here for performance reasons,
// as we only care about the case where an transaction was replaced entirely
// in a reorganization (which wipes vout entirely, as opposed to spending
@@ -119,7 +129,7 @@ bool CCoinsViewCache::HaveCoins(const uint256 &txid) {
return (it != cacheCoins.end() && !it->second.vout.empty());
}
-uint256 CCoinsViewCache::GetBestBlock() {
+uint256 CCoinsViewCache::GetBestBlock() const {
if (hashBlock == uint256(0))
hashBlock = base->GetBestBlock();
return hashBlock;
@@ -130,32 +140,34 @@ bool CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
return true;
}
-bool CCoinsViewCache::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlockIn) {
- for (CCoinsMap::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
- cacheCoins[it->first] = it->second;
+bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn) {
+ for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
+ cacheCoins[it->first].swap(it->second);
+ CCoinsMap::iterator itOld = it++;
+ mapCoins.erase(itOld);
+ }
hashBlock = hashBlockIn;
return true;
}
bool CCoinsViewCache::Flush() {
bool fOk = base->BatchWrite(cacheCoins, hashBlock);
- if (fOk)
- cacheCoins.clear();
+ cacheCoins.clear();
return fOk;
}
-unsigned int CCoinsViewCache::GetCacheSize() {
+unsigned int CCoinsViewCache::GetCacheSize() const {
return cacheCoins.size();
}
-const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input)
+const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) const
{
const CCoins &coins = GetCoins(input.prevout.hash);
assert(coins.IsAvailable(input.prevout.n));
return coins.vout[input.prevout.n];
}
-int64_t CCoinsViewCache::GetValueIn(const CTransaction& tx)
+int64_t CCoinsViewCache::GetValueIn(const CTransaction& tx) const
{
if (tx.IsCoinBase())
return 0;
@@ -167,7 +179,7 @@ int64_t CCoinsViewCache::GetValueIn(const CTransaction& tx)
return nResult;
}
-bool CCoinsViewCache::HaveInputs(const CTransaction& tx)
+bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
{
if (!tx.IsCoinBase()) {
// first check whether information about the prevout hash is available
@@ -188,7 +200,7 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx)
return true;
}
-double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight)
+double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
{
if (tx.IsCoinBase())
return 0.0;
diff --git a/src/coins.h b/src/coins.h
index ff60288163..08913531d8 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -276,26 +276,27 @@ class CCoinsView
{
public:
// Retrieve the CCoins (unspent transaction outputs) for a given txid
- virtual bool GetCoins(const uint256 &txid, CCoins &coins);
+ virtual bool GetCoins(const uint256 &txid, CCoins &coins) const;
// Modify the CCoins for a given txid
virtual bool SetCoins(const uint256 &txid, const CCoins &coins);
// Just check whether we have data for a given txid.
// This may (but cannot always) return true for fully spent transactions
- virtual bool HaveCoins(const uint256 &txid);
+ virtual bool HaveCoins(const uint256 &txid) const;
// Retrieve the block hash whose state this CCoinsView currently represents
- virtual uint256 GetBestBlock();
+ virtual uint256 GetBestBlock() const;
// Modify the currently active block hash
virtual bool SetBestBlock(const uint256 &hashBlock);
- // Do a bulk modification (multiple SetCoins + one SetBestBlock)
- virtual bool BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock);
+ // Do a bulk modification (multiple SetCoins + one SetBestBlock).
+ // The passed mapCoins can be modified.
+ virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
// Calculate statistics about the unspent transaction output set
- virtual bool GetStats(CCoinsStats &stats);
+ virtual bool GetStats(CCoinsStats &stats) const;
// As we use CCoinsViews polymorphically, have a virtual destructor
virtual ~CCoinsView() {}
@@ -310,14 +311,14 @@ protected:
public:
CCoinsViewBacked(CCoinsView &viewIn);
- bool GetCoins(const uint256 &txid, CCoins &coins);
+ bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool SetCoins(const uint256 &txid, const CCoins &coins);
- bool HaveCoins(const uint256 &txid);
- uint256 GetBestBlock();
+ bool HaveCoins(const uint256 &txid) const;
+ uint256 GetBestBlock() const;
bool SetBestBlock(const uint256 &hashBlock);
void SetBackend(CCoinsView &viewIn);
- bool BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock);
- bool GetStats(CCoinsStats &stats);
+ bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
+ bool GetStats(CCoinsStats &stats) const;
};
@@ -325,31 +326,36 @@ public:
class CCoinsViewCache : public CCoinsViewBacked
{
protected:
- uint256 hashBlock;
- CCoinsMap cacheCoins;
+
+ /* Make mutable so that we can "fill the cache" even from Get-methods
+ declared as "const". */
+ mutable uint256 hashBlock;
+ mutable CCoinsMap cacheCoins;
public:
CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false);
// Standard CCoinsView methods
- bool GetCoins(const uint256 &txid, CCoins &coins);
+ bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool SetCoins(const uint256 &txid, const CCoins &coins);
- bool HaveCoins(const uint256 &txid);
- uint256 GetBestBlock();
+ bool HaveCoins(const uint256 &txid) const;
+ uint256 GetBestBlock() const;
bool SetBestBlock(const uint256 &hashBlock);
- bool BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock);
+ bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
// Return a modifiable reference to a CCoins. Check HaveCoins first.
// Many methods explicitly require a CCoinsViewCache because of this method, to reduce
// copying.
CCoins &GetCoins(const uint256 &txid);
+ const CCoins &GetCoins(const uint256 &txid) const;
// Push the modifications applied to this cache to its base.
// Failure to call this method before destruction will cause the changes to be forgotten.
+ // If false is returned, the state of this cache (and its backing view) will be undefined.
bool Flush();
// Calculate the size of the cache (in number of transactions)
- unsigned int GetCacheSize();
+ unsigned int GetCacheSize() const;
/** Amount of bitcoins coming in to a transaction
Note that lightweight clients may not know anything besides the hash of previous transactions,
@@ -358,18 +364,19 @@ public:
@param[in] tx transaction for which we are checking input total
@return Sum of value of all inputs (scriptSigs)
*/
- int64_t GetValueIn(const CTransaction& tx);
+ int64_t GetValueIn(const CTransaction& tx) const;
// Check whether all prevouts of the transaction are present in the UTXO set represented by this view
- bool HaveInputs(const CTransaction& tx);
+ bool HaveInputs(const CTransaction& tx) const;
// Return priority of tx at height nHeight
- double GetPriority(const CTransaction &tx, int nHeight);
+ double GetPriority(const CTransaction &tx, int nHeight) const;
- const CTxOut &GetOutputFor(const CTxIn& input);
+ const CTxOut &GetOutputFor(const CTxIn& input) const;
private:
CCoinsMap::iterator FetchCoins(const uint256 &txid);
+ CCoinsMap::const_iterator FetchCoins(const uint256 &txid) const;
};
#endif
diff --git a/src/compat.h b/src/compat.h
index 52c7817130..4fc28a36e0 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -59,4 +59,29 @@ typedef u_int SOCKET;
#define SOCKET_ERROR -1
#endif
+#ifdef WIN32
+#ifndef S_IRUSR
+#define S_IRUSR 0400
+#define S_IWUSR 0200
+#endif
+#else
+#define MAX_PATH 1024
+#endif
+
+// As Solaris does not have the MSG_NOSIGNAL flag for send(2) syscall, it is defined as 0
+#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
+#define MSG_NOSIGNAL 0
+#endif
+
+#ifndef WIN32
+// PRIO_MAX is not defined on Solaris
+#ifndef PRIO_MAX
+#define PRIO_MAX 20
+#endif
+#define THREAD_PRIORITY_LOWEST PRIO_MAX
+#define THREAD_PRIORITY_BELOW_NORMAL 2
+#define THREAD_PRIORITY_NORMAL 0
+#define THREAD_PRIORITY_ABOVE_NORMAL (-2)
+#endif
+
#endif // _BITCOIN_COMPAT_H
diff --git a/src/core.cpp b/src/core.cpp
index 149b3532a1..71d6fea610 100644
--- a/src/core.cpp
+++ b/src/core.cpp
@@ -5,18 +5,13 @@
#include "core.h"
-#include "util.h"
+#include "tinyformat.h"
std::string COutPoint::ToString() const
{
return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n);
}
-void COutPoint::print() const
-{
- LogPrintf("%s\n", ToString());
-}
-
CTxIn::CTxIn(COutPoint prevoutIn, CScript scriptSigIn, unsigned int nSequenceIn)
{
prevout = prevoutIn;
@@ -46,11 +41,6 @@ std::string CTxIn::ToString() const
return str;
}
-void CTxIn::print() const
-{
- LogPrintf("%s\n", ToString());
-}
-
CTxOut::CTxOut(int64_t nValueIn, CScript scriptPubKeyIn)
{
nValue = nValueIn;
@@ -67,11 +57,6 @@ std::string CTxOut::ToString() const
return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30));
}
-void CTxOut::print() const
-{
- LogPrintf("%s\n", ToString());
-}
-
CFeeRate::CFeeRate(int64_t nFeePaid, size_t nSize)
{
if (nSize > 0)
@@ -92,8 +77,7 @@ int64_t CFeeRate::GetFee(size_t nSize) const
std::string CFeeRate::ToString() const
{
- std::string result = FormatMoney(nSatoshisPerK) + " BTC/kB";
- return result;
+ return strprintf("%d.%08d BTC/kB", nSatoshisPerK / COIN, nSatoshisPerK % COIN);
}
CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
@@ -171,11 +155,6 @@ std::string CTransaction::ToString() const
return str;
}
-void CTransaction::print() const
-{
- LogPrintf("%s", ToString());
-}
-
// Amount compression:
// * If the amount is 0, output 0
// * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9)
@@ -285,9 +264,10 @@ uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMer
return hash;
}
-void CBlock::print() const
+std::string CBlock::ToString() const
{
- LogPrintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
+ std::stringstream s;
+ s << strprintf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
GetHash().ToString(),
nVersion,
hashPrevBlock.ToString(),
@@ -296,11 +276,11 @@ void CBlock::print() const
vtx.size());
for (unsigned int i = 0; i < vtx.size(); i++)
{
- LogPrintf(" ");
- vtx[i].print();
+ s << " " << vtx[i].ToString() << "\n";
}
- LogPrintf(" vMerkleTree: ");
+ s << " vMerkleTree: ";
for (unsigned int i = 0; i < vMerkleTree.size(); i++)
- LogPrintf("%s ", vMerkleTree[i].ToString());
- LogPrintf("\n");
+ s << " " << vMerkleTree[i].ToString();
+ s << "\n";
+ return s.str();
}
diff --git a/src/core.h b/src/core.h
index fb64e6c08e..e3ceac97aa 100644
--- a/src/core.h
+++ b/src/core.h
@@ -14,6 +14,9 @@
class CTransaction;
+static const int64_t COIN = 100000000;
+static const int64_t CENT = 1000000;
+
/** No amount larger than this (in satoshi) is valid */
static const int64_t MAX_MONEY = 21000000 * COIN;
inline bool MoneyRange(int64_t nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
@@ -47,7 +50,6 @@ public:
}
std::string ToString() const;
- void print() const;
};
/** An inpoint - a combination of a transaction and an index n into its vin */
@@ -107,7 +109,6 @@ public:
}
std::string ToString() const;
- void print() const;
};
@@ -200,7 +201,6 @@ public:
}
std::string ToString() const;
- void print() const;
};
@@ -279,7 +279,6 @@ public:
}
std::string ToString() const;
- void print() const;
};
/** A mutable version of CTransaction. */
@@ -497,7 +496,7 @@ public:
std::vector<uint256> GetMerkleBranch(int nIndex) const;
static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex);
- void print() const;
+ std::string ToString() const;
};
diff --git a/src/core_write.cpp b/src/core_write.cpp
index 37dd69f7b8..b395b5c090 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -8,6 +8,7 @@
#include "core.h"
#include "serialize.h"
#include "util.h"
+#include "utilmoneystr.h"
#include "base58.h"
using namespace std;
diff --git a/src/crypter.cpp b/src/crypter.cpp
index 4c43e3a798..8aa2bb0517 100644
--- a/src/crypter.cpp
+++ b/src/crypter.cpp
@@ -5,6 +5,7 @@
#include "crypter.h"
#include "script.h"
+#include "util.h"
#include <string>
#include <vector>
@@ -152,6 +153,8 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
if (!SetCrypted())
return false;
+ bool keyPass = false;
+ bool keyFail = false;
CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin();
for (; mi != mapCryptedKeys.end(); ++mi)
{
@@ -159,16 +162,35 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
const std::vector<unsigned char> &vchCryptedSecret = (*mi).second.second;
CKeyingMaterial vchSecret;
if(!DecryptSecret(vMasterKeyIn, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
- return false;
+ {
+ keyFail = true;
+ break;
+ }
if (vchSecret.size() != 32)
- return false;
+ {
+ keyFail = true;
+ break;
+ }
CKey key;
key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
- if (key.GetPubKey() == vchPubKey)
+ if (key.GetPubKey() != vchPubKey)
+ {
+ keyFail = true;
break;
- return false;
+ }
+ keyPass = true;
+ if (fDecryptionThoroughlyChecked)
+ break;
+ }
+ if (keyPass && keyFail)
+ {
+ LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.");
+ assert(false);
}
+ if (keyFail || !keyPass)
+ return false;
vMasterKey = vMasterKeyIn;
+ fDecryptionThoroughlyChecked = true;
}
NotifyStatusChanged(this);
return true;
diff --git a/src/crypter.h b/src/crypter.h
index 4791428b48..f16fcef9c7 100644
--- a/src/crypter.h
+++ b/src/crypter.h
@@ -121,6 +121,9 @@ private:
// if fUseCrypto is false, vMasterKey must be empty
bool fUseCrypto;
+ // keeps track of whether Unlock has run a thourough check before
+ bool fDecryptionThoroughlyChecked;
+
protected:
bool SetCrypted();
@@ -130,7 +133,7 @@ protected:
bool Unlock(const CKeyingMaterial& vMasterKeyIn);
public:
- CCryptoKeyStore() : fUseCrypto(false)
+ CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false)
{
}
diff --git a/src/db.cpp b/src/db.cpp
index eb40f3cc40..8c139843a1 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -9,6 +9,7 @@
#include "hash.h"
#include "protocol.h"
#include "util.h"
+#include "utilstrencodings.h"
#include <stdint.h>
@@ -17,6 +18,7 @@
#endif
#include <boost/filesystem.hpp>
+#include <boost/thread.hpp>
#include <boost/version.hpp>
#include <openssl/rand.h>
diff --git a/src/db.h b/src/db.h
index 66d7f31917..bba267b84f 100644
--- a/src/db.h
+++ b/src/db.h
@@ -17,7 +17,6 @@
#include <boost/filesystem/path.hpp>
#include <db_cxx.h>
-class CAddrMan;
struct CBlockLocator;
class CDiskBlockIndex;
class COutPoint;
diff --git a/src/init.cpp b/src/init.cpp
index 8ae228bbbe..e972413c4b 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -19,6 +19,7 @@
#include "txdb.h"
#include "ui_interface.h"
#include "util.h"
+#include "utilmoneystr.h"
#ifdef ENABLE_WALLET
#include "db.h"
#include "wallet.h"
@@ -36,6 +37,7 @@
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
+#include <boost/thread.hpp>
#include <openssl/crypto.h>
using namespace boost;
@@ -247,7 +249,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += " -maxreceivebuffer=<n> " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000)") + "\n";
strUsage += " -maxsendbuffer=<n> " + _("Maximum per-connection send buffer, <n>*1000 bytes (default: 1000)") + "\n";
strUsage += " -onion=<ip:port> " + _("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: -proxy)") + "\n";
- strUsage += " -onlynet=<net> " + _("Only connect to nodes in network <net> (IPv4, IPv6 or Tor)") + "\n";
+ strUsage += " -onlynet=<net> " + _("Only connect to nodes in network <net> (ipv4, ipv6 or onion)") + "\n";
strUsage += " -permitbaremultisig " + _("Relay non-P2SH multisig (default: 1)") + "\n";
strUsage += " -port=<port> " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n";
strUsage += " -proxy=<ip:port> " + _("Connect through SOCKS5 proxy") + "\n";
@@ -1029,8 +1031,7 @@ bool AppInit2(boost::thread_group& threadGroup)
CBlock block;
ReadBlockFromDisk(block, pindex);
block.BuildMerkleTree();
- block.print();
- LogPrintf("\n");
+ LogPrintf("%s\n", block.ToString());
nFound++;
}
}
diff --git a/src/keystore.cpp b/src/keystore.cpp
index 81b7b076fa..72ae9b0a30 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -8,6 +8,7 @@
#include "crypter.h"
#include "key.h"
#include "script.h"
+#include "util.h"
#include <boost/foreach.hpp>
diff --git a/src/keystore.h b/src/keystore.h
index f10e24f36c..7aaf197cd7 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -8,21 +8,12 @@
#include "key.h"
#include "sync.h"
-#include "script.h" // for CNoDestination
#include <boost/signals2/signal.hpp>
#include <boost/variant.hpp>
class CScript;
-/** A txout script template with a specific destination. It is either:
- * * CNoDestination: no destination set
- * * CKeyID: TX_PUBKEYHASH destination
- * * CScriptID: TX_SCRIPTHASH destination
- * A CTxDestination is the internal data type encoded in a CBitcoinAddress
- */
-typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
-
/** A virtual base class for key stores */
class CKeyStore
{
diff --git a/src/leveldbwrapper.h b/src/leveldbwrapper.h
index 043a56bf38..452df92839 100644
--- a/src/leveldbwrapper.h
+++ b/src/leveldbwrapper.h
@@ -82,7 +82,7 @@ public:
CLevelDBWrapper(const boost::filesystem::path &path, size_t nCacheSize, bool fMemory = false, bool fWipe = false);
~CLevelDBWrapper();
- template<typename K, typename V> bool Read(const K& key, V& value) throw(leveldb_error) {
+ template<typename K, typename V> bool Read(const K& key, V& value) const throw(leveldb_error) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(ssKey.GetSerializeSize(key));
ssKey << key;
@@ -111,7 +111,7 @@ public:
return WriteBatch(batch, fSync);
}
- template<typename K> bool Exists(const K& key) throw(leveldb_error) {
+ template<typename K> bool Exists(const K& key) const throw(leveldb_error) {
CDataStream ssKey(SER_DISK, CLIENT_VERSION);
ssKey.reserve(ssKey.GetSerializeSize(key));
ssKey << key;
diff --git a/src/m4/ax_boost_base.m4 b/src/m4/ax_boost_base.m4
index e025a7e1ca..3f24d5ddc6 100644
--- a/src/m4/ax_boost_base.m4
+++ b/src/m4/ax_boost_base.m4
@@ -112,6 +112,12 @@ if test "x$want_boost" = "xyes"; then
;;
esac
+ dnl some arches may advertise a cpu type that doesn't line up with their
+ dnl prefix's cpu type. For example, uname may report armv7l while libs are
+ dnl installed to /usr/lib/arm-linux-gnueabihf. Try getting the compiler's
+ dnl value for an extra chance of finding the correct path.
+ libsubdirs="lib/`$CXX -dumpmachine 2>/dev/null` $libsubdirs"
+
dnl first we check the system location for boost libraries
dnl this location ist chosen if boost libraries are installed with the --layout=system option
dnl or if you install boost with RPM
diff --git a/src/m4/bitcoin_qt.m4 b/src/m4/bitcoin_qt.m4
index 4c1d40c394..e141033b19 100644
--- a/src/m4/bitcoin_qt.m4
+++ b/src/m4/bitcoin_qt.m4
@@ -48,8 +48,8 @@ dnl CAUTION: Do not use this inside of a conditional.
AC_DEFUN([BITCOIN_QT_INIT],[
dnl enable qt support
AC_ARG_WITH([gui],
- [AS_HELP_STRING([--with-gui],
- [with GUI (no|qt4|qt5|auto. default is auto, qt4 tried first.)])],
+ [AS_HELP_STRING([--with-gui@<:@=no|qt4|qt5|auto@:>@],
+ [build bitcoin-qt GUI (default=auto, qt4 tried first)])],
[
bitcoin_qt_want_version=$withval
if test x$bitcoin_qt_want_version = xyes; then
@@ -112,11 +112,7 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static])
if test x$qt_plugin_path != x; then
QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible"
- if test x$bitcoin_qt_got_major_vers == x5; then
- QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms"
- else
- QT_LIBS="$QT_LIBS -L$qt_plugin_path/codecs"
- fi
+ QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms"
fi
if test x$use_pkgconfig = xyes; then
PKG_CHECK_MODULES([QTPLATFORM], [Qt5PlatformSupport], [QT_LIBS="$QTPLATFORM_LIBS $QT_LIBS"])
@@ -141,6 +137,10 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[
else
if test x$TARGET_OS == xwindows; then
AC_DEFINE(QT_STATICPLUGIN, 1, [Define this symbol if qt plugins are static])
+ if test x$qt_plugin_path != x; then
+ QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible"
+ QT_LIBS="$QT_LIBS -L$qt_plugin_path/codecs"
+ fi
_BITCOIN_QT_CHECK_STATIC_PLUGINS([
Q_IMPORT_PLUGIN(qcncodecs)
Q_IMPORT_PLUGIN(qjpcodecs)
diff --git a/src/main.cpp b/src/main.cpp
index ba521b6b19..6567c77e93 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -20,9 +20,11 @@
#include <sstream>
+#include <boost/dynamic_bitset.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
+#include <boost/thread.hpp>
using namespace std;
using namespace boost;
@@ -643,7 +645,7 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
// 2. P2SH scripts with a crazy number of expensive
// CHECKSIG/CHECKMULTISIG operations
//
-bool AreInputsStandard(const CTransaction& tx, CCoinsViewCache& mapInputs)
+bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
if (tx.IsCoinBase())
return true; // Coinbases don't use vin normally
@@ -716,7 +718,7 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx)
return nSigOps;
}
-unsigned int GetP2SHSigOpCount(const CTransaction& tx, CCoinsViewCache& inputs)
+unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& inputs)
{
if (tx.IsCoinBase())
return 0;
@@ -956,9 +958,18 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
if (Params().RequireStandard() && !AreInputsStandard(tx, view))
return error("AcceptToMemoryPool: : nonstandard transaction input");
- // Note: if you modify this code to accept non-standard transactions, then
- // you should add code here to check that the transaction does a
- // reasonable number of ECDSA signature verifications.
+ // 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_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_TX_SIGOPS)
+ return state.DoS(0,
+ error("AcceptToMemoryPool : too many sigops %s, %d > %d",
+ hash.ToString(), nSigOps, MAX_TX_SIGOPS),
+ REJECT_NONSTANDARD, "bad-txns-too-many-sigops");
int64_t nValueOut = tx.GetValueOut();
int64_t nFees = nValueIn-nValueOut;
@@ -1013,7 +1024,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
pool.addUnchecked(hash, entry);
}
- g_signals.SyncTransaction(tx, NULL);
+ SyncWithWallets(tx, NULL);
return true;
}
@@ -1460,7 +1471,7 @@ bool VerifySignature(const CCoins& txFrom, const CTransaction& txTo, unsigned in
return CScriptCheck(txFrom, txTo, nIn, flags, nHashType)();
}
-bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, std::vector<CScriptCheck> *pvChecks)
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, std::vector<CScriptCheck> *pvChecks)
{
if (!tx.IsCoinBase())
{
@@ -1848,10 +1859,6 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
int64_t nTime3 = GetTimeMicros(); nTimeIndex += nTime3 - nTime2;
LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeIndex * 0.000001);
- // Watch for transactions paying to me
- BOOST_FOREACH(const CTransaction& tx, block.vtx)
- g_signals.SyncTransaction(tx, &block);
-
// Watch for changes to the previous coinbase transaction.
static uint256 hashPrevBestCoinBase;
g_signals.UpdatedTransaction(hashPrevBestCoinBase);
@@ -3052,7 +3059,7 @@ bool CVerifyDB::VerifyDB(int nCheckLevel, int nCheckDepth)
}
}
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
- if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= 2*nCoinCacheSize + 32000) {
+ if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= nCoinCacheSize) {
bool fClean = true;
if (!DisconnectBlock(block, state, pindex, coins, &fClean))
return error("VerifyDB() : *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
@@ -3228,7 +3235,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
}
}
uint64_t nRewind = blkdat.GetPos();
- while (blkdat.good() && !blkdat.eof()) {
+ while (!blkdat.eof()) {
boost::this_thread::interruption_point();
blkdat.SetPos(nRewind);
@@ -3512,6 +3519,75 @@ void static ProcessGetData(CNode* pfrom)
}
}
+struct CCoin {
+ uint32_t nTxVer; // Don't call this nVersion, that name has a special meaning inside IMPLEMENT_SERIALIZE
+ uint32_t nHeight;
+ CTxOut out;
+
+ IMPLEMENT_SERIALIZE(
+ READWRITE(nTxVer);
+ READWRITE(nHeight);
+ READWRITE(out);
+ )
+};
+
+bool ProcessGetUTXOs(const vector<COutPoint> &vOutPoints, bool fCheckMemPool, vector<unsigned char> *result, vector<CCoin> *resultCoins)
+{
+ // Defined by BIP 64.
+ //
+ // Allows a peer to retrieve the CTxOut structures corresponding to the given COutPoints.
+ // Note that this data is not authenticated by anything: this code could just invent any
+ // old rubbish and hand it back, with the peer being unable to tell unless they are checking
+ // the outpoints against some out of band data.
+ //
+ // Also the answer could change the moment after we give it. However some apps can tolerate
+ // this, because they're only using the result as a hint or are willing to trust the results
+ // based on something else. For example we may be a "trusted node" for the peer, or it may
+ // be checking the results given by several nodes for consistency, it may
+ // run the UTXOs returned against scriptSigs of transactions obtained elsewhere (after checking
+ // for a standard script form), and because the height in which the UTXO was defined is provided
+ // a client that has a map of heights to block headers (as SPV clients do, for recent blocks)
+ // can request the creating block via hash.
+ //
+ // IMPORTANT: Clients expect ordering to be preserved!
+ if (vOutPoints.size() > MAX_INV_SZ)
+ return error("message getutxos size() = %u", vOutPoints.size());
+
+ LogPrint("net", "getutxos for %d queries %s mempool\n", vOutPoints.size(), fCheckMemPool ? "with" : "without");
+
+ boost::dynamic_bitset<unsigned char> hits(vOutPoints.size());
+ {
+ LOCK2(cs_main, mempool.cs);
+ CCoinsViewMemPool cvMemPool(*pcoinsTip, mempool);
+ CCoinsViewCache view(fCheckMemPool ? cvMemPool : *pcoinsTip);
+ for (size_t i = 0; i < vOutPoints.size(); i++)
+ {
+ CCoins coins;
+ uint256 hash = vOutPoints[i].hash;
+ if (view.GetCoins(hash, coins))
+ {
+ mempool.pruneSpent(hash, coins);
+ if (coins.IsAvailable(vOutPoints[i].n))
+ {
+ hits[i] = true;
+ // Safe to index into vout here because IsAvailable checked if it's off the end of the array, or if
+ // n is valid but points to an already spent output (IsNull).
+ CCoin coin;
+ coin.nTxVer = coins.nVersion;
+ coin.nHeight = coins.nHeight;
+ coin.out = coins.vout.at(vOutPoints[i].n);
+ assert(!coin.out.IsNull());
+ resultCoins->push_back(coin);
+ }
+ }
+ }
+ }
+
+ boost::to_block_range(hits, std::back_inserter(*result));
+ return true;
+}
+
+
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived)
{
RandAddSeedPerfmon();
@@ -3559,7 +3635,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (!vRecv.empty())
vRecv >> addrFrom >> nNonce;
if (!vRecv.empty()) {
- vRecv >> pfrom->strSubVer;
+ vRecv >> LIMITED_STRING(pfrom->strSubVer, 256);
pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer);
}
if (!vRecv.empty())
@@ -3860,6 +3936,22 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
+ else if (strCommand == "getutxos")
+ {
+ bool fCheckMemPool;
+ vector<COutPoint> vOutPoints;
+ vRecv >> fCheckMemPool;
+ vRecv >> vOutPoints;
+
+ vector<unsigned char> bitmap;
+ vector<CCoin> outs;
+ if (ProcessGetUTXOs(vOutPoints, fCheckMemPool, &bitmap, &outs))
+ pfrom->PushMessage("utxos", chainActive.Height(), chainActive.Tip()->GetBlockHash(), bitmap, outs);
+ else
+ Misbehaving(pfrom->GetId(), 20);
+ }
+
+
else if (strCommand == "tx")
{
vector<uint256> vWorkQueue;
@@ -3959,7 +4051,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
vRecv >> block;
LogPrint("net", "received block %s peer=%d\n", block.GetHash().ToString(), pfrom->id);
- // block.print();
CInv inv(MSG_BLOCK, block.GetHash());
pfrom->AddInventoryKnown(inv);
@@ -4183,7 +4274,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (fDebug)
{
string strMsg; unsigned char ccode; string strReason;
- vRecv >> strMsg >> ccode >> strReason;
+ vRecv >> LIMITED_STRING(strMsg, CMessageHeader::COMMAND_SIZE) >> ccode >> LIMITED_STRING(strReason, 111);
ostringstream ss;
ss << strMsg << " code " << itostr(ccode) << ": " << strReason;
@@ -4194,10 +4285,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
vRecv >> hash;
ss << ": hash " << hash.ToString();
}
- // Truncate to reasonable length and sanitize before printing:
- string s = ss.str();
- if (s.size() > 111) s.erase(111, string::npos);
- LogPrint("net", "Reject %s\n", SanitizeString(s));
+ LogPrint("net", "Reject %s\n", SanitizeString(ss.str()));
}
}
@@ -4568,7 +4656,68 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
}
+bool CBlockUndo::WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock)
+{
+ // Open history file to append
+ CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
+ if (!fileout)
+ return error("CBlockUndo::WriteToDisk : OpenUndoFile failed");
+
+ // Write index header
+ unsigned int nSize = fileout.GetSerializeSize(*this);
+ fileout << FLATDATA(Params().MessageStart()) << nSize;
+
+ // Write undo data
+ long fileOutPos = ftell(fileout);
+ if (fileOutPos < 0)
+ return error("CBlockUndo::WriteToDisk : ftell failed");
+ pos.nPos = (unsigned int)fileOutPos;
+ fileout << *this;
+
+ // calculate & write checksum
+ CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
+ hasher << hashBlock;
+ hasher << *this;
+ fileout << hasher.GetHash();
+
+ // Flush stdio buffers and commit to disk before returning
+ fflush(fileout);
+ if (!IsInitialBlockDownload())
+ FileCommit(fileout);
+
+ return true;
+}
+
+bool CBlockUndo::ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock)
+{
+ // Open history file to read
+ CAutoFile filein = CAutoFile(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
+ if (!filein)
+ return error("CBlockUndo::ReadFromDisk : OpenBlockFile failed");
+
+ // Read block
+ uint256 hashChecksum;
+ try {
+ filein >> *this;
+ filein >> hashChecksum;
+ }
+ catch (std::exception &e) {
+ return error("%s : Deserialize or I/O error - %s", __func__, e.what());
+ }
+
+ // Verify checksum
+ CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
+ hasher << hashBlock;
+ hasher << *this;
+ if (hashChecksum != hasher.GetHash())
+ return error("CBlockUndo::ReadFromDisk : Checksum mismatch");
+
+ return true;
+}
+ std::string CBlockFileInfo::ToString() const {
+ return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst).c_str(), DateTimeStrFormat("%Y-%m-%d", nTimeLast).c_str());
+ }
diff --git a/src/main.h b/src/main.h
index a27020459a..e5357cbfdd 100644
--- a/src/main.h
+++ b/src/main.h
@@ -45,6 +45,8 @@ static const unsigned int MAX_STANDARD_TX_SIZE = 100000;
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
/** Maxiumum number of signature check operations in an IsStandard() P2SH script */
static const unsigned int MAX_P2SH_SIGOPS = 15;
+/** The maximum number of sigops we're willing to relay/mine in a single tx */
+static const unsigned int MAX_TX_SIGOPS = MAX_BLOCK_SIGOPS/5;
/** The maximum number of orphan transactions kept in memory */
static const unsigned int MAX_ORPHAN_TRANSACTIONS = MAX_BLOCK_SIZE/100;
/** Default for -maxorphanblocks, maximum number of orphan blocks kept in memory */
@@ -263,7 +265,7 @@ int64_t GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF
@param[in] mapInputs Map of previous transactions that have outputs we're spending
@return True if all inputs (scriptSigs) use only standard transaction forms
*/
-bool AreInputsStandard(const CTransaction& tx, CCoinsViewCache& mapInputs);
+bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
/** Count ECDSA signature operations the old-fashioned (pre-0.6) way
@return number of sigops this transaction's outputs will produce when spent
@@ -277,13 +279,13 @@ unsigned int GetLegacySigOpCount(const CTransaction& tx);
@return maximum number of sigops required to validate this transaction's inputs
@see CTransaction::FetchInputs
*/
-unsigned int GetP2SHSigOpCount(const CTransaction& tx, CCoinsViewCache& mapInputs);
+unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& mapInputs);
// Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
// This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it
// instead of being performed inline.
-bool CheckInputs(const CTransaction& tx, CValidationState &state, CCoinsViewCache &view, bool fScriptChecks = true,
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks = true,
unsigned int flags = STANDARD_SCRIPT_VERIFY_FLAGS,
std::vector<CScriptCheck> *pvChecks = NULL);
@@ -310,64 +312,8 @@ public:
READWRITE(vtxundo);
)
- bool WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock)
- {
- // Open history file to append
- CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
- if (!fileout)
- return error("CBlockUndo::WriteToDisk : OpenUndoFile failed");
-
- // Write index header
- unsigned int nSize = fileout.GetSerializeSize(*this);
- fileout << FLATDATA(Params().MessageStart()) << nSize;
-
- // Write undo data
- long fileOutPos = ftell(fileout);
- if (fileOutPos < 0)
- return error("CBlockUndo::WriteToDisk : ftell failed");
- pos.nPos = (unsigned int)fileOutPos;
- fileout << *this;
-
- // calculate & write checksum
- CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
- hasher << hashBlock;
- hasher << *this;
- fileout << hasher.GetHash();
-
- // Flush stdio buffers and commit to disk before returning
- fflush(fileout);
- if (!IsInitialBlockDownload())
- FileCommit(fileout);
-
- return true;
- }
-
- bool ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock)
- {
- // Open history file to read
- CAutoFile filein = CAutoFile(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION);
- if (!filein)
- return error("CBlockUndo::ReadFromDisk : OpenBlockFile failed");
-
- // Read block
- uint256 hashChecksum;
- try {
- filein >> *this;
- filein >> hashChecksum;
- }
- catch (std::exception &e) {
- return error("%s : Deserialize or I/O error - %s", __func__, e.what());
- }
-
- // Verify checksum
- CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION);
- hasher << hashBlock;
- hasher << *this;
- if (hashChecksum != hasher.GetHash())
- return error("CBlockUndo::ReadFromDisk : Checksum mismatch");
-
- return true;
- }
+ bool WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock);
+ bool ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock);
};
@@ -623,9 +569,7 @@ public:
SetNull();
}
- std::string ToString() const {
- return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst).c_str(), DateTimeStrFormat("%Y-%m-%d", nTimeLast).c_str());
- }
+ std::string ToString() const;
// update statistics (does not update nSize)
void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) {
@@ -837,11 +781,6 @@ public:
GetBlockHash().ToString());
}
- void print() const
- {
- LogPrintf("%s\n", ToString());
- }
-
// Check whether this block index entry is valid up to the passed validity level.
bool IsValid(enum BlockStatus nUpTo = BLOCK_VALID_TRANSACTIONS) const
{
@@ -933,11 +872,6 @@ public:
hashPrev.ToString());
return str;
}
-
- void print() const
- {
- LogPrintf("%s\n", ToString());
- }
};
/** Capture information about block/transaction validation */
diff --git a/src/miner.cpp b/src/miner.cpp
index ec56c71192..8696edcf6e 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -3,8 +3,6 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include <inttypes.h>
-
#include "miner.h"
#include "core.h"
@@ -12,10 +10,14 @@
#include "main.h"
#include "net.h"
#include "pow.h"
+#include "util.h"
+#include "utilmoneystr.h"
#ifdef ENABLE_WALLET
#include "wallet.h"
#endif
+#include <boost/thread.hpp>
+
using namespace std;
//////////////////////////////////////////////////////////////////////////////
@@ -42,14 +44,6 @@ public:
COrphan(const CTransaction* ptxIn) : ptx(ptxIn), feeRate(0), dPriority(0)
{
}
-
- void print() const
- {
- LogPrintf("COrphan(hash=%s, dPriority=%.1f, fee=%s)\n",
- ptx->GetHash().ToString(), dPriority, feeRate.ToString());
- BOOST_FOREACH(uint256 hash, setDependsOn)
- LogPrintf(" setDependsOn %s\n", hash.ToString());
- }
};
uint64_t nLastBlockTx = 0;
@@ -402,18 +396,9 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey)
return CreateNewBlock(scriptPubKey);
}
-bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
+bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
{
- uint256 hash = pblock->GetHash();
- uint256 hashTarget = uint256().SetCompact(pblock->nBits);
-
- if (hash > hashTarget)
- return false;
-
- //// debug print
- LogPrintf("BitcoinMiner:\n");
- LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex());
- pblock->print();
+ LogPrintf("%s\n", pblock->ToString());
LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue));
// Found a solution
@@ -500,7 +485,9 @@ void static BitcoinMiner(CWallet *pwallet)
assert(hash == pblock->GetHash());
SetThreadPriority(THREAD_PRIORITY_NORMAL);
- CheckWork(pblock, *pwallet, reservekey);
+ LogPrintf("BitcoinMiner:\n");
+ LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex());
+ ProcessBlockFound(pblock, *pwallet, reservekey);
SetThreadPriority(THREAD_PRIORITY_LOWEST);
// In regression test mode, stop mining after a block is found.
diff --git a/src/net.cpp b/src/net.cpp
index 62124514c8..e2adba8517 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -28,6 +28,7 @@
#endif
#include <boost/filesystem.hpp>
+#include <boost/thread.hpp>
// Dump addresses to peers.dat every 15 minutes (900s)
#define DUMP_ADDRESSES_INTERVAL 900
@@ -66,7 +67,7 @@ namespace {
//
bool fDiscover = true;
bool fListen = true;
-uint64_t nLocalServices = NODE_NETWORK;
+uint64_t nLocalServices = NODE_NETWORK | NODE_GETUTXOS;
CCriticalSection cs_mapLocalHost;
map<CNetAddr, LocalServiceInfo> mapLocalHost;
static bool vfReachable[NET_MAX] = {};
@@ -307,12 +308,18 @@ bool IsLocal(const CService& addr)
return mapLocalHost.count(addr) > 0;
}
+/** check whether a given network is one we can probably connect to */
+bool IsReachable(enum Network net)
+{
+ LOCK(cs_mapLocalHost);
+ return vfReachable[net] && !vfLimited[net];
+}
+
/** check whether a given address is in a network we can probably connect to */
bool IsReachable(const CNetAddr& addr)
{
- LOCK(cs_mapLocalHost);
enum Network net = addr.GetNetwork();
- return vfReachable[net] && !vfLimited[net];
+ return IsReachable(net);
}
bool GetMyExternalIP2(const CService& addrConnect, const char* pszGet, const char* pszKeyword, CNetAddr& ipRet)
@@ -368,7 +375,7 @@ bool GetMyExternalIP(CNetAddr& ipRet)
const char* pszKeyword;
for (int nLookup = 0; nLookup <= 1; nLookup++)
- for (int nHost = 1; nHost <= 2; nHost++)
+ for (int nHost = 1; nHost <= 1; nHost++)
{
// We should be phasing out our use of sites like these. If we need
// replacements, we should ask for volunteers to put this simple
@@ -393,25 +400,6 @@ bool GetMyExternalIP(CNetAddr& ipRet)
pszKeyword = "Address:";
}
- else if (nHost == 2)
- {
- addrConnect = CService("74.208.43.192", 80); // www.showmyip.com
-
- if (nLookup == 1)
- {
- CService addrIP("www.showmyip.com", 80, true);
- if (addrIP.IsValid())
- addrConnect = addrIP;
- }
-
- pszGet = "GET /simple/ HTTP/1.1\r\n"
- "Host: www.showmyip.com\r\n"
- "User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\n"
- "Connection: close\r\n"
- "\r\n";
-
- pszKeyword = NULL; // Returns just IP address
- }
if (GetMyExternalIP2(addrConnect, pszGet, pszKeyword, ipRet))
return true;
@@ -2050,3 +2038,157 @@ bool CAddrDB::Read(CAddrMan& addr)
return true;
}
+
+unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
+unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); }
+
+CNode::CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn, bool fInboundIn) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), setAddrKnown(5000)
+{
+ nServices = 0;
+ hSocket = hSocketIn;
+ nRecvVersion = INIT_PROTO_VERSION;
+ nLastSend = 0;
+ nLastRecv = 0;
+ nSendBytes = 0;
+ nRecvBytes = 0;
+ nTimeConnected = GetTime();
+ addr = addrIn;
+ addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
+ nVersion = 0;
+ strSubVer = "";
+ fWhitelisted = false;
+ fOneShot = false;
+ fClient = false; // set by version message
+ fInbound = fInboundIn;
+ fNetworkNode = false;
+ fSuccessfullyConnected = false;
+ fDisconnect = false;
+ nRefCount = 0;
+ nSendSize = 0;
+ nSendOffset = 0;
+ hashContinue = 0;
+ pindexLastGetBlocksBegin = 0;
+ hashLastGetBlocksEnd = 0;
+ nStartingHeight = -1;
+ fStartSync = false;
+ fGetAddr = false;
+ fRelayTxes = false;
+ setInventoryKnown.max_size(SendBufferSize() / 1000);
+ pfilter = new CBloomFilter();
+ nPingNonceSent = 0;
+ nPingUsecStart = 0;
+ nPingUsecTime = 0;
+ fPingQueued = false;
+
+ {
+ LOCK(cs_nLastNodeId);
+ id = nLastNodeId++;
+ }
+
+ if (fLogIPs)
+ LogPrint("net", "Added connection to %s peer=%d\n", addrName, id);
+ else
+ LogPrint("net", "Added connection peer=%d\n", id);
+
+ // Be shy and don't send version until we hear
+ if (hSocket != INVALID_SOCKET && !fInbound)
+ PushVersion();
+
+ GetNodeSignals().InitializeNode(GetId(), this);
+}
+
+CNode::~CNode()
+{
+ CloseSocket(hSocket);
+
+ if (pfilter)
+ delete pfilter;
+
+ GetNodeSignals().FinalizeNode(GetId());
+}
+
+void CNode::AskFor(const CInv& inv)
+{
+ // We're using mapAskFor as a priority queue,
+ // the key is the earliest time the request can be sent
+ int64_t nRequestTime;
+ limitedmap<CInv, int64_t>::const_iterator it = mapAlreadyAskedFor.find(inv);
+ if (it != mapAlreadyAskedFor.end())
+ nRequestTime = it->second;
+ else
+ nRequestTime = 0;
+ LogPrint("net", "askfor %s %d (%s) peer=%d\n", inv.ToString(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str(), id);
+
+ // Make sure not to reuse time indexes to keep things in the same order
+ int64_t nNow = GetTimeMicros() - 1000000;
+ static int64_t nLastTime;
+ ++nLastTime;
+ nNow = std::max(nNow, nLastTime);
+ nLastTime = nNow;
+
+ // Each retry is 2 minutes after the last
+ nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
+ if (it != mapAlreadyAskedFor.end())
+ mapAlreadyAskedFor.update(it, nRequestTime);
+ else
+ mapAlreadyAskedFor.insert(std::make_pair(inv, nRequestTime));
+ mapAskFor.insert(std::make_pair(nRequestTime, inv));
+}
+
+void CNode::BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend)
+{
+ ENTER_CRITICAL_SECTION(cs_vSend);
+ assert(ssSend.size() == 0);
+ ssSend << CMessageHeader(pszCommand, 0);
+ LogPrint("net", "sending: %s ", pszCommand);
+}
+
+void CNode::AbortMessage() UNLOCK_FUNCTION(cs_vSend)
+{
+ ssSend.clear();
+
+ LEAVE_CRITICAL_SECTION(cs_vSend);
+
+ LogPrint("net", "(aborted)\n");
+}
+
+void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
+{
+ // The -*messagestest options are intentionally not documented in the help message,
+ // since they are only used during development to debug the networking code and are
+ // not intended for end-users.
+ if (mapArgs.count("-dropmessagestest") && GetRand(GetArg("-dropmessagestest", 2)) == 0)
+ {
+ LogPrint("net", "dropmessages DROPPING SEND MESSAGE\n");
+ AbortMessage();
+ return;
+ }
+ if (mapArgs.count("-fuzzmessagestest"))
+ Fuzz(GetArg("-fuzzmessagestest", 10));
+
+ if (ssSend.size() == 0)
+ return;
+
+ // Set the size
+ unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE;
+ memcpy((char*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], &nSize, sizeof(nSize));
+
+ // Set the checksum
+ uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end());
+ unsigned int nChecksum = 0;
+ memcpy(&nChecksum, &hash, sizeof(nChecksum));
+ assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum));
+ memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], &nChecksum, sizeof(nChecksum));
+
+ LogPrint("net", "(%d bytes) peer=%d\n", nSize, id);
+
+ std::deque<CSerializeData>::iterator it = vSendMsg.insert(vSendMsg.end(), CSerializeData());
+ ssSend.GetAndClear(*it);
+ nSendSize += (*it).size();
+
+ // If write queue empty, attempt "optimistic write"
+ if (it == vSendMsg.begin())
+ SocketSendData(this);
+
+ LEAVE_CRITICAL_SECTION(cs_vSend);
+}
diff --git a/src/net.h b/src/net.h
index a8795a4760..bfad32b2c1 100644
--- a/src/net.h
+++ b/src/net.h
@@ -16,7 +16,7 @@
#include "random.h"
#include "sync.h"
#include "uint256.h"
-#include "util.h"
+#include "utilstrencodings.h"
#include <deque>
#include <stdint.h>
@@ -25,6 +25,7 @@
#include <arpa/inet.h>
#endif
+#include <boost/filesystem/path.hpp>
#include <boost/foreach.hpp>
#include <boost/signals2/signal.hpp>
@@ -51,8 +52,8 @@ static const bool DEFAULT_UPNP = USE_UPNP;
static const bool DEFAULT_UPNP = false;
#endif
-inline unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
-inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); }
+unsigned int ReceiveFloodSize();
+unsigned int SendBufferSize();
void AddOneShot(std::string strDest);
bool RecvLine(SOCKET hSocket, std::string& strLine);
@@ -106,6 +107,7 @@ bool AddLocal(const CNetAddr& addr, int nScore = LOCAL_NONE);
bool SeenLocal(const CService& addr);
bool IsLocal(const CService& addr);
bool GetLocal(CService &addr, const CNetAddr *paddrPeer = NULL);
+bool IsReachable(enum Network net);
bool IsReachable(const CNetAddr &addr);
void SetReachable(enum Network net, bool fFlag = true);
CAddress GetLocalAddress(const CNetAddr *paddrPeer = NULL);
@@ -299,70 +301,8 @@ public:
// Whether a ping is requested.
bool fPingQueued;
- CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false) : ssSend(SER_NETWORK, INIT_PROTO_VERSION), setAddrKnown(5000)
- {
- nServices = 0;
- hSocket = hSocketIn;
- nRecvVersion = INIT_PROTO_VERSION;
- nLastSend = 0;
- nLastRecv = 0;
- nSendBytes = 0;
- nRecvBytes = 0;
- nTimeConnected = GetTime();
- addr = addrIn;
- addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
- nVersion = 0;
- strSubVer = "";
- fWhitelisted = false;
- fOneShot = false;
- fClient = false; // set by version message
- fInbound = fInboundIn;
- fNetworkNode = false;
- fSuccessfullyConnected = false;
- fDisconnect = false;
- nRefCount = 0;
- nSendSize = 0;
- nSendOffset = 0;
- hashContinue = 0;
- pindexLastGetBlocksBegin = 0;
- hashLastGetBlocksEnd = 0;
- nStartingHeight = -1;
- fStartSync = false;
- fGetAddr = false;
- fRelayTxes = false;
- setInventoryKnown.max_size(SendBufferSize() / 1000);
- pfilter = new CBloomFilter();
- nPingNonceSent = 0;
- nPingUsecStart = 0;
- nPingUsecTime = 0;
- fPingQueued = false;
-
- {
- LOCK(cs_nLastNodeId);
- id = nLastNodeId++;
- }
-
- if (fLogIPs)
- LogPrint("net", "Added connection to %s peer=%d\n", addrName, id);
- else
- LogPrint("net", "Added connection peer=%d\n", id);
-
- // Be shy and don't send version until we hear
- if (hSocket != INVALID_SOCKET && !fInbound)
- PushVersion();
-
- GetNodeSignals().InitializeNode(GetId(), this);
- }
-
- ~CNode()
- {
- CloseSocket(hSocket);
-
- if (pfilter)
- delete pfilter;
-
- GetNodeSignals().FinalizeNode(GetId());
- }
+ CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false);
+ ~CNode();
private:
// Network usage totals
@@ -451,96 +391,16 @@ public:
}
}
- void AskFor(const CInv& inv)
- {
- // We're using mapAskFor as a priority queue,
- // the key is the earliest time the request can be sent
- int64_t nRequestTime;
- limitedmap<CInv, int64_t>::const_iterator it = mapAlreadyAskedFor.find(inv);
- if (it != mapAlreadyAskedFor.end())
- nRequestTime = it->second;
- else
- nRequestTime = 0;
- LogPrint("net", "askfor %s %d (%s) peer=%d\n", inv.ToString(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str(), id);
-
- // Make sure not to reuse time indexes to keep things in the same order
- int64_t nNow = GetTimeMicros() - 1000000;
- static int64_t nLastTime;
- ++nLastTime;
- nNow = std::max(nNow, nLastTime);
- nLastTime = nNow;
-
- // Each retry is 2 minutes after the last
- nRequestTime = std::max(nRequestTime + 2 * 60 * 1000000, nNow);
- if (it != mapAlreadyAskedFor.end())
- mapAlreadyAskedFor.update(it, nRequestTime);
- else
- mapAlreadyAskedFor.insert(std::make_pair(inv, nRequestTime));
- mapAskFor.insert(std::make_pair(nRequestTime, inv));
- }
-
-
+ void AskFor(const CInv& inv);
// TODO: Document the postcondition of this function. Is cs_vSend locked?
- void BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend)
- {
- ENTER_CRITICAL_SECTION(cs_vSend);
- assert(ssSend.size() == 0);
- ssSend << CMessageHeader(pszCommand, 0);
- LogPrint("net", "sending: %s ", pszCommand);
- }
+ void BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend);
// TODO: Document the precondition of this function. Is cs_vSend locked?
- void AbortMessage() UNLOCK_FUNCTION(cs_vSend)
- {
- ssSend.clear();
-
- LEAVE_CRITICAL_SECTION(cs_vSend);
-
- LogPrint("net", "(aborted)\n");
- }
+ void AbortMessage() UNLOCK_FUNCTION(cs_vSend);
// TODO: Document the precondition of this function. Is cs_vSend locked?
- void EndMessage() UNLOCK_FUNCTION(cs_vSend)
- {
- // The -*messagestest options are intentionally not documented in the help message,
- // since they are only used during development to debug the networking code and are
- // not intended for end-users.
- if (mapArgs.count("-dropmessagestest") && GetRand(GetArg("-dropmessagestest", 2)) == 0)
- {
- LogPrint("net", "dropmessages DROPPING SEND MESSAGE\n");
- AbortMessage();
- return;
- }
- if (mapArgs.count("-fuzzmessagestest"))
- Fuzz(GetArg("-fuzzmessagestest", 10));
-
- if (ssSend.size() == 0)
- return;
-
- // Set the size
- unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE;
- memcpy((char*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], &nSize, sizeof(nSize));
-
- // Set the checksum
- uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end());
- unsigned int nChecksum = 0;
- memcpy(&nChecksum, &hash, sizeof(nChecksum));
- assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum));
- memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], &nChecksum, sizeof(nChecksum));
-
- LogPrint("net", "(%d bytes) peer=%d\n", nSize, id);
-
- std::deque<CSerializeData>::iterator it = vSendMsg.insert(vSendMsg.end(), CSerializeData());
- ssSend.GetAndClear(*it);
- nSendSize += (*it).size();
-
- // If write queue empty, attempt "optimistic write"
- if (it == vSendMsg.begin())
- SocketSendData(this);
-
- LEAVE_CRITICAL_SECTION(cs_vSend);
- }
+ void EndMessage() UNLOCK_FUNCTION(cs_vSend);
void PushVersion();
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 1031e7e38a..d5821d4465 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -13,6 +13,7 @@
#include "sync.h"
#include "uint256.h"
#include "util.h"
+#include "utilstrencodings.h"
#ifdef HAVE_GETADDRINFO_A
#include <netdb.h>
@@ -27,6 +28,7 @@
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
#include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
+#include <boost/thread.hpp>
#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
@@ -47,10 +49,20 @@ enum Network ParseNetwork(std::string net) {
boost::to_lower(net);
if (net == "ipv4") return NET_IPV4;
if (net == "ipv6") return NET_IPV6;
- if (net == "tor") return NET_TOR;
+ if (net == "tor" || net == "onion") return NET_TOR;
return NET_UNROUTABLE;
}
+std::string GetNetworkName(enum Network net) {
+ switch(net)
+ {
+ case NET_IPV4: return "ipv4";
+ case NET_IPV6: return "ipv6";
+ case NET_TOR: return "onion";
+ default: return "";
+ }
+}
+
void SplitHostPort(std::string in, int &portOut, std::string &hostOut) {
size_t colon = in.find_last_of(':');
// if a : is found, and it either follows a [...], or no other : is in the string, treat it as port separator
@@ -864,11 +876,6 @@ uint64_t CNetAddr::GetHash() const
return nRet;
}
-void CNetAddr::print() const
-{
- LogPrintf("CNetAddr(%s)\n", ToString());
-}
-
// private extensions to enum Network, only returned by GetExtNetwork,
// and only used in GetReachabilityFrom
static const int NET_UNKNOWN = NET_MAX + 0;
@@ -1097,11 +1104,6 @@ std::string CService::ToString() const
return ToStringIPPort();
}
-void CService::print() const
-{
- LogPrintf("CService(%s)\n", ToString());
-}
-
void CService::SetPort(unsigned short portIn)
{
port = portIn;
diff --git a/src/netbase.h b/src/netbase.h
index 7d83e35344..2df3c4474d 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -26,7 +26,7 @@ extern bool fNameLookup;
enum Network
{
- NET_UNROUTABLE,
+ NET_UNROUTABLE = 0,
NET_IPV4,
NET_IPV6,
NET_TOR,
@@ -80,7 +80,6 @@ class CNetAddr
bool GetInAddr(struct in_addr* pipv4Addr) const;
std::vector<unsigned char> GetGroup() const;
int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const;
- void print() const;
CNetAddr(const struct in6_addr& pipv6Addr);
bool GetIn6Addr(struct in6_addr* pipv6Addr) const;
@@ -145,7 +144,6 @@ class CService : public CNetAddr
std::string ToString() const;
std::string ToStringPort() const;
std::string ToStringIPPort() const;
- void print() const;
CService(const struct in6_addr& ipv6Addr, unsigned short port);
CService(const struct sockaddr_in6& addr);
@@ -164,6 +162,7 @@ class CService : public CNetAddr
typedef CService proxyType;
enum Network ParseNetwork(std::string net);
+std::string GetNetworkName(enum Network net);
void SplitHostPort(std::string in, int &portOut, std::string &hostOut);
bool SetProxy(enum Network net, CService addrProxy);
bool GetProxy(enum Network net, proxyType &proxyInfoOut);
diff --git a/src/noui.cpp b/src/noui.cpp
index 32c861b0d9..8b00fd4057 100644
--- a/src/noui.cpp
+++ b/src/noui.cpp
@@ -8,6 +8,7 @@
#include "ui_interface.h"
#include "util.h"
+#include <cstdio>
#include <stdint.h>
#include <string>
diff --git a/src/pow.cpp b/src/pow.cpp
index c0d0a7ca20..b091cbec3d 100644
--- a/src/pow.cpp
+++ b/src/pow.cpp
@@ -9,6 +9,7 @@
#include "core.h"
#include "main.h"
#include "uint256.h"
+#include "util.h"
unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock)
{
diff --git a/src/protocol.cpp b/src/protocol.cpp
index 87b2f23873..341de0602a 100644
--- a/src/protocol.cpp
+++ b/src/protocol.cpp
@@ -144,9 +144,3 @@ std::string CInv::ToString() const
{
return strprintf("%s %s", GetCommand(), hash.ToString());
}
-
-void CInv::print() const
-{
- LogPrintf("CInv(%s)\n", ToString());
-}
-
diff --git a/src/protocol.h b/src/protocol.h
index 1f23274299..94d313e9c0 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -64,6 +64,7 @@ class CMessageHeader
enum
{
NODE_NETWORK = (1 << 0),
+ NODE_GETUTXOS = (1 << 1),
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
// isn't getting used, or one not being used much, and notify the
@@ -98,8 +99,6 @@ class CAddress : public CService
READWRITE(*pip);
)
- void print() const;
-
// TODO: make private (improves encapsulation)
public:
uint64_t nServices;
@@ -130,7 +129,6 @@ class CInv
bool IsKnownType() const;
const char* GetCommand() const;
std::string ToString() const;
- void print() const;
// TODO: make private (improves encapsulation)
public:
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index a43e7cb756..6cc6b99ceb 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -33,6 +33,7 @@
#include <stdint.h>
#include <boost/filesystem/operations.hpp>
+#include <boost/thread.hpp>
#include <QApplication>
#include <QDebug>
#include <QLibraryInfo>
@@ -414,8 +415,8 @@ void BitcoinApplication::initializeResult(int retval)
{
walletModel = new WalletModel(pwalletMain, optionsModel);
- window->addWallet("~Default", walletModel);
- window->setCurrentWallet("~Default");
+ window->addWallet(BitcoinGUI::DEFAULT_WALLET, walletModel);
+ window->setCurrentWallet(BitcoinGUI::DEFAULT_WALLET);
connect(walletModel, SIGNAL(coinsSent(CWallet*,SendCoinsRecipient,QByteArray)),
paymentServer, SLOT(fetchPaymentACK(CWallet*,const SendCoinsRecipient&,QByteArray)));
diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc
index 9a7003938b..42bb091e25 100644
--- a/src/qt/bitcoin.qrc
+++ b/src/qt/bitcoin.qrc
@@ -4,7 +4,6 @@
<file alias="address-book">res/icons/address-book.png</file>
<file alias="quit">res/icons/quit.png</file>
<file alias="send">res/icons/send.png</file>
- <file alias="toolbar">res/icons/toolbar.png</file>
<file alias="connect_0">res/icons/connect0_16.png</file>
<file alias="connect_1">res/icons/connect1_16.png</file>
<file alias="connect_2">res/icons/connect2_16.png</file>
@@ -27,7 +26,6 @@
<file alias="editcopy">res/icons/editcopy.png</file>
<file alias="add">res/icons/add.png</file>
<file alias="bitcoin_testnet">res/icons/bitcoin_testnet.png</file>
- <file alias="toolbar_testnet">res/icons/toolbar_testnet.png</file>
<file alias="edit">res/icons/edit.png</file>
<file alias="history">res/icons/history.png</file>
<file alias="overview">res/icons/overview.png</file>
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index e3257e859c..68d42ce64b 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -24,6 +24,7 @@
#endif
#include "init.h"
+#include "util.h"
#include "ui_interface.h"
#include <iostream>
@@ -61,10 +62,35 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) :
QMainWindow(parent),
clientModel(0),
walletFrame(0),
+ unitDisplayControl(0),
+ labelEncryptionIcon(0),
+ labelConnectionsIcon(0),
+ labelBlocksIcon(0),
+ progressBarLabel(0),
+ progressBar(0),
+ progressDialog(0),
+ appMenuBar(0),
+ overviewAction(0),
+ historyAction(0),
+ quitAction(0),
+ sendCoinsAction(0),
+ usedSendingAddressesAction(0),
+ usedReceivingAddressesAction(0),
+ signMessageAction(0),
+ verifyMessageAction(0),
+ aboutAction(0),
+ receiveCoinsAction(0),
+ optionsAction(0),
+ toggleHideAction(0),
encryptWalletAction(0),
+ backupWalletAction(0),
changePassphraseAction(0),
aboutQtAction(0),
+ openRPCConsoleAction(0),
+ openAction(0),
+ showHelpMessageAction(0),
trayIcon(0),
+ trayIconMenu(0),
notificator(0),
rpcConsole(0),
prevBlocks(0),
@@ -425,8 +451,12 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
walletFrame->setClientModel(clientModel);
}
#endif
-
- this->unitDisplayControl->setOptionsModel(clientModel->getOptionsModel());
+ unitDisplayControl->setOptionsModel(clientModel->getOptionsModel());
+ } else {
+ // Disable possibility to show main window via action
+ toggleHideAction->setEnabled(false);
+ // Disable context menu on tray icon
+ trayIconMenu->clear();
}
}
@@ -479,12 +509,12 @@ void BitcoinGUI::createTrayIcon(bool fIsTestnet)
if (!fIsTestnet)
{
trayIcon->setToolTip(tr("Bitcoin Core client"));
- trayIcon->setIcon(QIcon(":/icons/toolbar"));
+ trayIcon->setIcon(QIcon(":/icons/bitcoin"));
}
else
{
trayIcon->setToolTip(tr("Bitcoin Core client") + " " + tr("[testnet]"));
- trayIcon->setIcon(QIcon(":/icons/toolbar_testnet"));
+ trayIcon->setIcon(QIcon(":/icons/bitcoin_testnet"));
}
trayIcon->show();
@@ -495,7 +525,6 @@ void BitcoinGUI::createTrayIcon(bool fIsTestnet)
void BitcoinGUI::createTrayIconMenu()
{
- QMenu *trayIconMenu;
#ifndef Q_OS_MAC
// return if trayIcon is unset (only on non-Mac OSes)
if (!trayIcon)
@@ -536,7 +565,7 @@ void BitcoinGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
if(reason == QSystemTrayIcon::Trigger)
{
// Click on system tray icon triggers show/hide of the main window
- toggleHideAction->trigger();
+ toggleHidden();
}
}
#endif
@@ -922,6 +951,7 @@ void BitcoinGUI::showNormalIfMinimized(bool fToggleHidden)
{
if(!clientModel)
return;
+
// activateWindow() (sometimes) helps with keyboard focus on Windows
if (isHidden())
{
@@ -1006,9 +1036,10 @@ void BitcoinGUI::unsubscribeFromCoreSignals()
uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
}
-UnitDisplayStatusBarControl::UnitDisplayStatusBarControl():QLabel()
+UnitDisplayStatusBarControl::UnitDisplayStatusBarControl() :
+ optionsModel(0),
+ menu(0)
{
- optionsModel = 0;
createContextMenu();
setToolTip(tr("Unit to show amounts in. Click to select another unit."));
}
@@ -1068,4 +1099,3 @@ void UnitDisplayStatusBarControl::onMenuSelection(QAction* action)
optionsModel->setDisplayUnit(action->data());
}
}
-
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 30dd7ae317..30b05cb7d9 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -103,6 +103,7 @@ private:
QAction *showHelpMessageAction;
QSystemTrayIcon *trayIcon;
+ QMenu *trayIconMenu;
Notificator *notificator;
RPCConsole *rpcConsole;
@@ -219,6 +220,7 @@ protected:
private:
OptionsModel *optionsModel;
QMenu* menu;
+
/** Shows context menu with Display Unit options by the mouse coordinates */
void onDisplayUnitsClicked(const QPoint& point);
/** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 4c21eb5594..9c9ff5b3a1 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -13,6 +13,7 @@
#include "main.h"
#include "net.h"
#include "ui_interface.h"
+#include "util.h"
#include <stdint.h>
diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui
index 7784a862d7..53d416ef38 100644
--- a/src/qt/forms/overviewpage.ui
+++ b/src/qt/forms/overviewpage.ui
@@ -13,8 +13,8 @@
<property name="windowTitle">
<string>Form</string>
</property>
- <layout class="QFormLayout" name="formLayout_3">
- <item row="0" column="0" colspan="2">
+ <layout class="QVBoxLayout" name="topLayout">
+ <item>
<widget class="QLabel" name="labelAlerts">
<property name="visible">
<bool>false</bool>
@@ -30,7 +30,7 @@
</property>
</widget>
</item>
- <item row="1" column="1">
+ <item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,1">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 7837e4229e..304177ee11 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -381,12 +381,6 @@ void openDebugLogfile()
QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathDebug)));
}
-ToolTipToRichTextFilter::ToolTipToRichTextFilter(int size_threshold, QObject *parent) :
- QObject(parent), size_threshold(size_threshold)
-{
-
-}
-
void SubstituteFonts()
{
#if defined(Q_OS_MAC)
@@ -407,6 +401,13 @@ void SubstituteFonts()
#endif
}
+ToolTipToRichTextFilter::ToolTipToRichTextFilter(int size_threshold, QObject *parent) :
+ QObject(parent),
+ size_threshold(size_threshold)
+{
+
+}
+
bool ToolTipToRichTextFilter::eventFilter(QObject *obj, QEvent *evt)
{
if(evt->type() == QEvent::ToolTipChange)
@@ -809,7 +810,7 @@ QString formatDurationStr(int secs)
return strList.join(" ");
}
-QString formatServicesStr(uint64_t mask)
+QString formatServicesStr(quint64 mask)
{
QStringList strList;
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index 83739a5f13..67e11e59a0 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -102,14 +102,13 @@ namespace GUIUtil
// Open debug.log
void openDebugLogfile();
+ // Replace invalid default fonts with known good ones
+ void SubstituteFonts();
+
/** Qt event filter that intercepts ToolTipChange events, and replaces the tooltip with a rich text
representation if needed. This assures that Qt can word-wrap long tooltip messages.
Tooltips longer than the provided size threshold (in characters) are wrapped.
*/
-
- // Replace invalid default fonts with known good ones
- void SubstituteFonts();
-
class ToolTipToRichTextFilter : public QObject
{
Q_OBJECT
@@ -181,7 +180,7 @@ namespace GUIUtil
QString formatDurationStr(int secs);
/* Format CNodeStats.nServices bitmask into a user-readable string */
- QString formatServicesStr(uint64_t mask);
+ QString formatServicesStr(quint64 mask);
/* Format a CNodeCombinedStats.dPingTime into a user-readable string or display N/A, if 0*/
QString formatPingTime(double dPingTime);
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index fd1d446f9b..c775a7f8d6 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -21,6 +21,7 @@
#include "wallet.h" // for CWallet::minTxFee
#endif
+#include <boost/thread.hpp>
#include <QDir>
#include <QIntValidator>
#include <QLocale>
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index a9f1566d62..f6a4b599de 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -11,6 +11,7 @@
#include "base58.h"
#include "ui_interface.h"
+#include "util.h"
#include "wallet.h"
#include <cstdlib>
diff --git a/src/qt/res/icons/toolbar.png b/src/qt/res/icons/toolbar.png
deleted file mode 100644
index c82d96519c..0000000000
--- a/src/qt/res/icons/toolbar.png
+++ /dev/null
Binary files differ
diff --git a/src/qt/res/icons/toolbar_testnet.png b/src/qt/res/icons/toolbar_testnet.png
deleted file mode 100644
index 5995bc0667..0000000000
--- a/src/qt/res/icons/toolbar_testnet.png
+++ /dev/null
Binary files differ
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 4f6e3169f5..8258e719a3 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -15,6 +15,7 @@
#include "transactionrecord.h"
#include "timedata.h"
#include "ui_interface.h"
+#include "util.h"
#include "wallet.h"
#include <stdint.h>
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index 5fb0da145d..7df9d1bc2d 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -10,9 +10,10 @@
#include "clientmodel.h"
#include "guiutil.h"
-#include "clientversion.h"
#include "init.h"
-#include "util.h"
+#include "version.h"
+
+#include <stdio.h>
#include <QLabel>
#include <QRegExp>
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 30c9ecc96b..92c22f5692 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -31,7 +31,6 @@ WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *p
transactionTableModel(0),
recentRequestsTableModel(0),
cachedBalance(0), cachedUnconfirmedBalance(0), cachedImmatureBalance(0),
- cachedNumTransactions(0),
cachedEncryptionStatus(Unencrypted),
cachedNumBlocks(0)
{
@@ -102,18 +101,6 @@ qint64 WalletModel::getWatchImmatureBalance() const
return wallet->GetImmatureWatchOnlyBalance();
}
-int WalletModel::getNumTransactions() const
-{
- int numTransactions = 0;
- {
- LOCK(wallet->cs_wallet);
- // the size of mapWallet contains the number of unique transaction IDs
- // (e.g. payments to yourself generate 2 transactions, but both share the same transaction ID)
- numTransactions = wallet->mapWallet.size();
- }
- return numTransactions;
-}
-
void WalletModel::updateStatus()
{
EncryptionStatus newEncryptionStatus = getEncryptionStatus();
@@ -181,13 +168,6 @@ void WalletModel::updateTransaction(const QString &hash, int status)
// Balance and number of transactions might have changed
checkBalanceChanged();
-
- int newNumTransactions = getNumTransactions();
- if(cachedNumTransactions != newNumTransactions)
- {
- cachedNumTransactions = newNumTransactions;
- emit numTransactionsChanged(newNumTransactions);
- }
}
void WalletModel::updateAddressBook(const QString &address, const QString &label,
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index 1dad716061..b3a401e4cc 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -132,7 +132,6 @@ public:
qint64 getWatchBalance() const;
qint64 getWatchUnconfirmedBalance() const;
qint64 getWatchImmatureBalance() const;
- int getNumTransactions() const;
EncryptionStatus getEncryptionStatus() const;
bool processingQueuedTransactions() { return fProcessingQueuedTransactions; }
@@ -216,7 +215,6 @@ private:
qint64 cachedWatchOnlyBalance;
qint64 cachedWatchUnconfBalance;
qint64 cachedWatchImmatureBalance;
- qint64 cachedNumTransactions;
EncryptionStatus cachedEncryptionStatus;
int cachedNumBlocks;
@@ -231,9 +229,6 @@ signals:
void balanceChanged(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance,
qint64 watchOnlyBalance, qint64 watchUnconfBalance, qint64 watchImmatureBalance);
- // Number of transactions in wallet changed
- void numTransactionsChanged(int count);
-
// Encryption status of wallet changed
void encryptionStatusChanged(int status);
diff --git a/src/random.cpp b/src/random.cpp
index 0d20d205ac..22c942acc0 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -8,12 +8,14 @@
#ifdef WIN32
#include "compat.h" // for Windows API
#endif
+#include "serialize.h" // for begin_ptr(vec)
#include "util.h" // for LogPrint()
+#include "utilstrencodings.h" // for GetTime()
#ifndef WIN32
#include <sys/time.h>
#endif
-
+#include <limits>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/rand.h>
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 1e5198b85c..58cab14045 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -7,6 +7,7 @@
#include "main.h"
#include "rpcserver.h"
#include "sync.h"
+#include "util.h"
#include <stdint.h>
@@ -531,3 +532,27 @@ Value getchaintips(const Array& params, bool fHelp)
return res;
}
+
+Value getmempoolinfo(const Array& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "getmempoolinfo\n"
+ "\nReturns details on the active state of the TX memory pool.\n"
+ "\nResult:\n"
+ "{\n"
+ " \"size\": xxxxx (numeric) Current tx count\n"
+ " \"bytes\": xxxxx (numeric) Sum of all tx sizes\n"
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("getmempoolinfo", "")
+ + HelpExampleRpc("getmempoolinfo", "")
+ );
+
+ Object ret;
+ ret.push_back(Pair("size", (int64_t) mempool.size()));
+ ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize()));
+
+ return ret;
+}
+
diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp
index ff2361482b..e68ddee040 100644
--- a/src/rpcdump.cpp
+++ b/src/rpcdump.cpp
@@ -7,6 +7,8 @@
#include "init.h"
#include "main.h"
#include "sync.h"
+#include "utiltime.h"
+#include "util.h"
#include "wallet.h"
#include <fstream>
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index edab427cbf..6e508abcda 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -11,6 +11,7 @@
#include "miner.h"
#include "pow.h"
#include "core_io.h"
+#include "util.h"
#ifdef ENABLE_WALLET
#include "db.h"
#include "wallet.h"
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index 88e7c4ab07..2baa481c4e 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -338,6 +338,26 @@ Value getnettotals(const Array& params, bool fHelp)
return obj;
}
+static Array GetNetworksInfo()
+{
+ Array networks;
+ for(int n=0; n<NET_MAX; ++n)
+ {
+ enum Network network = static_cast<enum Network>(n);
+ if(network == NET_UNROUTABLE)
+ continue;
+ proxyType proxy;
+ Object obj;
+ GetProxy(network, proxy);
+ obj.push_back(Pair("name", GetNetworkName(network)));
+ obj.push_back(Pair("limited", IsLimited(network)));
+ obj.push_back(Pair("reachable", IsReachable(network)));
+ obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.ToStringIPPort() : string()));
+ networks.push_back(obj);
+ }
+ return networks;
+}
+
Value getnetworkinfo(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
@@ -351,7 +371,13 @@ Value getnetworkinfo(const Array& params, bool fHelp)
" \"localservices\": \"xxxxxxxxxxxxxxxx\", (string) the services we offer to the network\n"
" \"timeoffset\": xxxxx, (numeric) the time offset\n"
" \"connections\": xxxxx, (numeric) the number of connections\n"
- " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n"
+ " \"networks\": [ (array) information per network\n"
+ " \"name\": \"xxx\", (string) network (ipv4, ipv6 or onion)\n"
+ " \"limited\": xxx, (boolean) is the network limited using -onlynet?\n"
+ " \"reachable\": xxx, (boolean) is the network reachable?\n"
+ " \"proxy\": \"host:port\" (string) the proxy that is used for this network, or empty if none\n"
+ " },\n"
+ " ],\n"
" \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in btc/kb\n"
" \"localaddresses\": [, (array) list of local addresses\n"
" \"address\": \"xxxx\", (string) network address\n"
@@ -364,16 +390,13 @@ Value getnetworkinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getnetworkinfo", "")
);
- proxyType proxy;
- GetProxy(NET_IPV4, proxy);
-
Object obj;
obj.push_back(Pair("version", (int)CLIENT_VERSION));
obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION));
obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices)));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
- obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.ToStringIPPort() : string())));
+ obj.push_back(Pair("networks", GetNetworksInfo()));
obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
Array localAddresses;
{
diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp
index 643208b3b6..808b9bbd2a 100644
--- a/src/rpcprotocol.cpp
+++ b/src/rpcprotocol.cpp
@@ -6,6 +6,10 @@
#include "rpcprotocol.h"
#include "util.h"
+#include "tinyformat.h"
+#include "utilstrencodings.h"
+#include "utiltime.h"
+#include "version.h"
#include <stdint.h>
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 763615120a..7cd704193d 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -738,9 +738,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
if (!fHaveMempool && !fHaveChain) {
// push to local node and sync with wallets
CValidationState state;
- if (AcceptToMemoryPool(mempool, state, tx, false, NULL, !fOverrideFees))
- SyncWithWallets(tx, NULL);
- else {
+ if (!AcceptToMemoryPool(mempool, state, tx, false, NULL, !fOverrideFees)) {
if(state.IsInvalid())
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
else
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index 56064941f6..c9133bd3d2 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -23,6 +23,7 @@
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/shared_ptr.hpp>
+#include <boost/thread.hpp>
#include "json/json_spirit_writer_template.h"
using namespace boost;
@@ -82,6 +83,11 @@ void RPCTypeCheck(const Object& o,
}
}
+static inline int64_t roundint64(double d)
+{
+ return (int64_t)(d > 0 ? d + 0.5 : d - 0.5);
+}
+
int64_t AmountFromValue(const Value& value)
{
double dAmount = value.get_real();
@@ -256,6 +262,7 @@ static const CRPCCommand vRPCCommands[] =
{ "blockchain", "getblockhash", &getblockhash, true, false, false },
{ "blockchain", "getchaintips", &getchaintips, true, false, false },
{ "blockchain", "getdifficulty", &getdifficulty, true, false, false },
+ { "blockchain", "getmempoolinfo", &getmempoolinfo, true, true, false },
{ "blockchain", "getrawmempool", &getrawmempool, true, false, false },
{ "blockchain", "gettxout", &gettxout, true, false, false },
{ "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, false, false },
@@ -848,11 +855,10 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn,
if (!HTTPAuthorized(mapHeaders))
{
LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string());
- /* Deter brute-forcing short passwords.
+ /* Deter brute-forcing
If this results in a DoS the user really
shouldn't have their RPC port exposed. */
- if (mapArgs["-rpcpassword"].size() < 20)
- MilliSleep(250);
+ MilliSleep(250);
conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush;
return false;
diff --git a/src/rpcserver.h b/src/rpcserver.h
index 2248e8aeb2..b850d15d4e 100644
--- a/src/rpcserver.h
+++ b/src/rpcserver.h
@@ -200,6 +200,7 @@ extern json_spirit::Value getblockcount(const json_spirit::Array& params, bool f
extern json_spirit::Value getbestblockhash(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getdifficulty(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value settxfee(const json_spirit::Array& params, bool fHelp);
+extern json_spirit::Value getmempoolinfo(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getrawmempool(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getblockhash(const json_spirit::Array& params, bool fHelp);
extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp);
diff --git a/src/script.cpp b/src/script.cpp
index 39ae001db8..28c50a1358 100644
--- a/src/script.cpp
+++ b/src/script.cpp
@@ -18,8 +18,9 @@
#include "util.h"
#include <boost/foreach.hpp>
-#include <boost/tuple/tuple.hpp>
+#include <boost/thread.hpp>
#include <boost/tuple/tuple_comparison.hpp>
+#include <boost/tuple/tuple.hpp>
using namespace std;
using namespace boost;
@@ -1444,18 +1445,6 @@ unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
return nResult;
}
-
-class CKeyStoreIsMineVisitor : public boost::static_visitor<bool>
-{
-private:
- const CKeyStore *keystore;
-public:
- CKeyStoreIsMineVisitor(const CKeyStore *keystoreIn) : keystore(keystoreIn) { }
- bool operator()(const CNoDestination &dest) const { return false; }
- bool operator()(const CKeyID &keyID) const { return keystore->HaveKey(keyID); }
- bool operator()(const CScriptID &scriptID) const { return keystore->HaveCScript(scriptID); }
-};
-
isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest)
{
CScript script;
@@ -1886,9 +1875,11 @@ bool CScript::IsPushOnly() const
const_iterator pc = begin();
while (pc < end())
{
+ // Note how a script with an invalid PUSHDATA returns False.
opcodetype opcode;
if (!GetOp(pc, opcode))
return false;
+
// Note that IsPushOnly() *does* consider OP_RESERVED to be a
// push-type opcode, however execution of OP_RESERVED fails, so
// it's not relevant to P2SH as the scriptSig would fail prior to
diff --git a/src/script.h b/src/script.h
index 7cb863d1c9..462e3f2302 100644
--- a/src/script.h
+++ b/src/script.h
@@ -7,7 +7,8 @@
#define H_BITCOIN_SCRIPT
#include "key.h"
-#include "util.h"
+#include "utilstrencodings.h"
+#include "tinyformat.h"
#include <stdexcept>
#include <stdint.h>
@@ -730,6 +731,12 @@ public:
{
return CScriptID(Hash160(*this));
}
+
+ void clear()
+ {
+ // The default std::vector::clear() does not release memory.
+ std::vector<unsigned char>().swap(*this);
+ }
};
/** Compact serializer for scripts.
diff --git a/src/serialize.h b/src/serialize.h
index f876efd9b5..17cb724bee 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -68,7 +68,7 @@ inline const T* end_ptr(const std::vector<T,TAl>& v)
/////////////////////////////////////////////////////////////////
//
// Templates for serializing to anything that looks like a stream,
-// i.e. anything that supports .read(char*, int) and .write(char*, int)
+// i.e. anything that supports .read(char*, size_t) and .write(char*, size_t)
//
enum
@@ -334,8 +334,9 @@ I ReadVarInt(Stream& is)
}
}
-#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj)))
-#define VARINT(obj) REF(WrapVarInt(REF(obj)))
+#define FLATDATA(obj) REF(CFlatData((char*)&(obj), (char*)&(obj) + sizeof(obj)))
+#define VARINT(obj) REF(WrapVarInt(REF(obj)))
+#define LIMITED_STRING(obj,n) REF(LimitedString< n >(REF(obj)))
/** Wrapper for serializing arrays and POD.
*/
@@ -398,6 +399,40 @@ public:
}
};
+template<size_t Limit>
+class LimitedString
+{
+protected:
+ std::string& string;
+public:
+ LimitedString(std::string& string) : string(string) {}
+
+ template<typename Stream>
+ void Unserialize(Stream& s, int, int=0)
+ {
+ size_t size = ReadCompactSize(s);
+ if (size > Limit) {
+ throw std::ios_base::failure("String length limit exceeded");
+ }
+ string.resize(size);
+ if (size != 0)
+ s.read((char*)&string[0], size);
+ }
+
+ template<typename Stream>
+ void Serialize(Stream& s, int, int=0) const
+ {
+ WriteCompactSize(s, string.size());
+ if (!string.empty())
+ s.write((char*)&string[0], string.size());
+ }
+
+ unsigned int GetSerializeSize(int, int=0) const
+ {
+ return GetSizeOfCompactSize(string.size()) + string.size();
+ }
+};
+
template<typename I>
CVarInt<I> WrapVarInt(I& n) { return CVarInt<I>(n); }
@@ -841,7 +876,7 @@ public:
CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {}
- CSizeComputer& write(const char *psz, int nSize)
+ CSizeComputer& write(const char *psz, size_t nSize)
{
this->nSize += nSize;
return *this;
@@ -870,8 +905,6 @@ protected:
typedef CSerializeData vector_type;
vector_type vch;
unsigned int nReadPos;
- short state;
- short exceptmask;
public:
int nType;
int nVersion;
@@ -923,8 +956,6 @@ public:
nReadPos = 0;
nType = nTypeIn;
nVersion = nVersionIn;
- state = 0;
- exceptmask = std::ios::badbit | std::ios::failbit;
}
CDataStream& operator+=(const CDataStream& b)
@@ -1047,19 +1078,7 @@ public:
//
// Stream subset
//
- void setstate(short bits, const char* psz)
- {
- state |= bits;
- if (state & exceptmask)
- throw std::ios_base::failure(psz);
- }
-
bool eof() const { return size() == 0; }
- bool fail() const { return state & (std::ios::badbit | std::ios::failbit); }
- bool good() const { return !eof() && (state == 0); }
- void clear(short n) { state = n; } // name conflict with vector clear()
- short exceptions() { return exceptmask; }
- short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CDataStream"); return prev; }
CDataStream* rdbuf() { return this; }
int in_avail() { return size(); }
@@ -1070,18 +1089,15 @@ public:
void ReadVersion() { *this >> nVersion; }
void WriteVersion() { *this << nVersion; }
- CDataStream& read(char* pch, int nSize)
+ CDataStream& read(char* pch, size_t nSize)
{
// Read from the beginning of the buffer
- assert(nSize >= 0);
unsigned int nReadPosNext = nReadPos + nSize;
if (nReadPosNext >= vch.size())
{
if (nReadPosNext > vch.size())
{
- setstate(std::ios::failbit, "CDataStream::read() : end of data");
- memset(pch, 0, nSize);
- nSize = vch.size() - nReadPos;
+ throw std::ios_base::failure("CDataStream::read() : end of data");
}
memcpy(pch, &vch[nReadPos], nSize);
nReadPos = 0;
@@ -1101,7 +1117,7 @@ public:
if (nReadPosNext >= vch.size())
{
if (nReadPosNext > vch.size())
- setstate(std::ios::failbit, "CDataStream::ignore() : end of data");
+ throw std::ios_base::failure("CDataStream::ignore() : end of data");
nReadPos = 0;
vch.clear();
return (*this);
@@ -1110,10 +1126,9 @@ public:
return (*this);
}
- CDataStream& write(const char* pch, int nSize)
+ CDataStream& write(const char* pch, size_t nSize)
{
// Write to the end of the buffer
- assert(nSize >= 0);
vch.insert(vch.end(), pch, pch + nSize);
return (*this);
}
@@ -1174,8 +1189,6 @@ class CAutoFile
{
protected:
FILE* file;
- short state;
- short exceptmask;
public:
int nType;
int nVersion;
@@ -1185,8 +1198,6 @@ public:
file = filenew;
nType = nTypeIn;
nVersion = nVersionIn;
- state = 0;
- exceptmask = std::ios::badbit | std::ios::failbit;
}
~CAutoFile()
@@ -1213,19 +1224,6 @@ public:
//
// Stream subset
//
- void setstate(short bits, const char* psz)
- {
- state |= bits;
- if (state & exceptmask)
- throw std::ios_base::failure(psz);
- }
-
- bool fail() const { return state & (std::ios::badbit | std::ios::failbit); }
- bool good() const { return state == 0; }
- void clear(short n = 0) { state = n; }
- short exceptions() { return exceptmask; }
- short exceptions(short mask) { short prev = exceptmask; exceptmask = mask; setstate(0, "CAutoFile"); return prev; }
-
void SetType(int n) { nType = n; }
int GetType() { return nType; }
void SetVersion(int n) { nVersion = n; }
@@ -1238,7 +1236,7 @@ public:
if (!file)
throw std::ios_base::failure("CAutoFile::read : file handle is NULL");
if (fread(pch, 1, nSize, file) != nSize)
- setstate(std::ios::failbit, feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed");
+ throw std::ios_base::failure(feof(file) ? "CAutoFile::read : end of file" : "CAutoFile::read : fread failed");
return (*this);
}
@@ -1247,7 +1245,7 @@ public:
if (!file)
throw std::ios_base::failure("CAutoFile::write : file handle is NULL");
if (fwrite(pch, 1, nSize, file) != nSize)
- setstate(std::ios::failbit, "CAutoFile::write : write failed");
+ throw std::ios_base::failure("CAutoFile::write : write failed");
return (*this);
}
@@ -1292,16 +1290,7 @@ private:
uint64_t nRewind; // how many bytes we guarantee to rewind
std::vector<char> vchBuf; // the buffer
- short state;
- short exceptmask;
-
protected:
- void setstate(short bits, const char *psz) {
- state |= bits;
- if (state & exceptmask)
- throw std::ios_base::failure(psz);
- }
-
// read data from the source to fill the buffer
bool Fill() {
unsigned int pos = nSrcPos % vchBuf.size();
@@ -1313,8 +1302,7 @@ protected:
return false;
size_t read = fread((void*)&vchBuf[pos], 1, readNow, src);
if (read == 0) {
- setstate(std::ios_base::failbit, feof(src) ? "CBufferedFile::Fill : end of file" : "CBufferedFile::Fill : fread failed");
- return false;
+ throw std::ios_base::failure(feof(src) ? "CBufferedFile::Fill : end of file" : "CBufferedFile::Fill : fread failed");
} else {
nSrcPos += read;
return true;
@@ -1327,12 +1315,7 @@ public:
CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) :
src(fileIn), nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0),
- state(0), exceptmask(std::ios_base::badbit | std::ios_base::failbit), nType(nTypeIn), nVersion(nVersionIn) {
- }
-
- // check whether no error occurred
- bool good() const {
- return state == 0;
+ nType(nTypeIn), nVersion(nVersionIn) {
}
// check whether we're at the end of the source file
@@ -1391,7 +1374,6 @@ public:
nLongPos = ftell(src);
nSrcPos = nLongPos;
nReadPos = nLongPos;
- state = 0;
return true;
}
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index 5e17555e7a..4ecf6e2535 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -14,6 +14,7 @@
#include "pow.h"
#include "script.h"
#include "serialize.h"
+#include "util.h"
#include <stdint.h>
diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp
index b16f3f7f57..4af87cf8ef 100644
--- a/src/test/alert_tests.cpp
+++ b/src/test/alert_tests.cpp
@@ -11,6 +11,7 @@
#include "serialize.h"
#include "util.h"
+#include "utilstrencodings.h"
#include "version.h"
#include <fstream>
@@ -83,7 +84,7 @@ struct ReadAlerts
std::vector<unsigned char> vch(alert_tests::alertTests, alert_tests::alertTests + sizeof(alert_tests::alertTests));
CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
try {
- while (stream.good())
+ while (!stream.eof())
{
CAlert alert;
stream >> alert;
diff --git a/src/test/allocator_tests.cpp b/src/test/allocator_tests.cpp
index 2752a0b215..69888da3df 100644
--- a/src/test/allocator_tests.cpp
+++ b/src/test/allocator_tests.cpp
@@ -4,6 +4,8 @@
#include "util.h"
+#include "allocators.h"
+
#include <boost/test/unit_test.hpp>
BOOST_AUTO_TEST_SUITE(allocator_tests)
diff --git a/src/test/base32_tests.cpp b/src/test/base32_tests.cpp
index 87473585e3..68617abbdd 100644
--- a/src/test/base32_tests.cpp
+++ b/src/test/base32_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "util.h"
+#include "utilstrencodings.h"
#include <boost/test/unit_test.hpp>
diff --git a/src/test/base64_tests.cpp b/src/test/base64_tests.cpp
index d4a23d9aa0..f2bf3326ad 100644
--- a/src/test/base64_tests.cpp
+++ b/src/test/base64_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "util.h"
+#include "utilstrencodings.h"
#include <boost/test/unit_test.hpp>
diff --git a/src/test/bctest.py b/src/test/bctest.py
new file mode 100644
index 0000000000..1839f4fef4
--- /dev/null
+++ b/src/test/bctest.py
@@ -0,0 +1,53 @@
+# Copyright 2014 BitPay, Inc.
+# Distributed under the MIT/X11 software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+import subprocess
+import os
+import json
+import sys
+
+def bctest(testDir, testObj):
+ execargs = testObj['exec']
+
+ stdinCfg = None
+ inputData = None
+ if "input" in testObj:
+ filename = testDir + "/" + testObj['input']
+ inputData = open(filename).read()
+ stdinCfg = subprocess.PIPE
+
+ outputFn = None
+ outputData = None
+ if "output_cmp" in testObj:
+ outputFn = testObj['output_cmp']
+ outputData = open(testDir + "/" + outputFn).read()
+
+ proc = subprocess.Popen(execargs, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ try:
+ outs = proc.communicate(input=inputData)
+ except OSError:
+ print("OSError, Failed to execute " + execargs[0])
+ sys.exit(1)
+
+ if outputData and (outs[0] != outputData):
+ print("Output data mismatch for " + outputFn)
+ sys.exit(1)
+
+ wantRC = 0
+ if "return_code" in testObj:
+ wantRC = testObj['return_code']
+ if proc.returncode != wantRC:
+ print("Return code mismatch for " + outputFn)
+ sys.exit(1)
+
+def bctester(testDir, input_basename):
+ input_filename = testDir + "/" + input_basename
+ raw_data = open(input_filename).read()
+ input_data = json.loads(raw_data)
+
+ for testObj in input_data:
+ bctest(testDir, testObj)
+
+ sys.exit(0)
+
diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py
new file mode 100755
index 0000000000..40690c2fed
--- /dev/null
+++ b/src/test/bitcoin-util-test.py
@@ -0,0 +1,12 @@
+#!/usr/bin/python
+# Copyright 2014 BitPay, Inc.
+# Distributed under the MIT/X11 software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+import os
+import bctest
+
+if __name__ == '__main__':
+ bctest.bctester(os.environ["srcdir"] + "/test/data",
+ "bitcoin-util-test.json")
+
diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp
index 10352240f4..fdea12846a 100644
--- a/src/test/checkblock_tests.cpp
+++ b/src/test/checkblock_tests.cpp
@@ -9,6 +9,7 @@
#include "main.h"
+#include "utiltime.h"
#include <cstdio>
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index a17278b803..a3eec270ee 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -6,7 +6,7 @@
#include "crypto/sha1.h"
#include "crypto/sha2.h"
#include "random.h"
-#include "util.h"
+#include "utilstrencodings.h"
#include <vector>
diff --git a/src/test/data/bitcoin-util-test.json b/src/test/data/bitcoin-util-test.json
new file mode 100644
index 0000000000..7db87d7c11
--- /dev/null
+++ b/src/test/data/bitcoin-util-test.json
@@ -0,0 +1,38 @@
+[
+ { "exec": ["./bitcoin-tx", "-create"],
+ "output_cmp": "blanktx.hex"
+ },
+ { "exec": ["./bitcoin-tx", "-"],
+ "input": "blanktx.hex",
+ "output_cmp": "blanktx.hex"
+ },
+ { "exec": ["./bitcoin-tx", "-", "delin=1"],
+ "input": "tx394b54bb.hex",
+ "output_cmp": "tt-delin1-out.hex"
+ },
+ { "exec": ["./bitcoin-tx", "-", "delin=31"],
+ "input": "tx394b54bb.hex",
+ "return_code": 1
+ },
+ { "exec": ["./bitcoin-tx", "-", "delout=1"],
+ "input": "tx394b54bb.hex",
+ "output_cmp": "tt-delout1-out.hex"
+ },
+ { "exec": ["./bitcoin-tx", "-", "delout=2"],
+ "input": "tx394b54bb.hex",
+ "return_code": 1
+ },
+ { "exec": ["./bitcoin-tx", "-", "locktime=317000"],
+ "input": "tx394b54bb.hex",
+ "output_cmp": "tt-locktime317000-out.hex"
+ },
+ { "exec":
+ ["./bitcoin-tx", "-create",
+ "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
+ "in=bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c:18",
+ "in=22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc:1",
+ "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
+ "outaddr=4:1P8yWvZW8jVihP1bzHeqfE4aoXNX8AVa46"],
+ "output_cmp": "txcreate1.hex"
+ }
+]
diff --git a/src/test/data/blanktx.hex b/src/test/data/blanktx.hex
new file mode 100644
index 0000000000..36b6f00fb6
--- /dev/null
+++ b/src/test/data/blanktx.hex
@@ -0,0 +1 @@
+01000000000000000000
diff --git a/src/test/data/tt-delin1-out.hex b/src/test/data/tt-delin1-out.hex
new file mode 100644
index 0000000000..42ad840f43
--- /dev/null
+++ b/src/test/data/tt-delin1-out.hex
@@ -0,0 +1 @@
+0100000014fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac00000000
diff --git a/src/test/data/tt-delout1-out.hex b/src/test/data/tt-delout1-out.hex
new file mode 100644
index 0000000000..cc60c3fac6
--- /dev/null
+++ b/src/test/data/tt-delout1-out.hex
@@ -0,0 +1 @@
+0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0160f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac00000000
diff --git a/src/test/data/tt-locktime317000-out.hex b/src/test/data/tt-locktime317000-out.hex
new file mode 100644
index 0000000000..287f420a40
--- /dev/null
+++ b/src/test/data/tt-locktime317000-out.hex
@@ -0,0 +1 @@
+0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac48d60400
diff --git a/src/test/data/tx394b54bb.hex b/src/test/data/tx394b54bb.hex
new file mode 100644
index 0000000000..33f26cb4d6
--- /dev/null
+++ b/src/test/data/tx394b54bb.hex
@@ -0,0 +1 @@
+0100000015fd5c23522d31761c50175453daa6edaabe47a602a592d39ce933d8271a1a87274c0100006c493046022100b4251ecd63778a3dde0155abe4cd162947620ae9ee45a874353551092325b116022100db307baf4ff3781ec520bd18f387948cedd15dc27bafe17c894b0fe6ffffcafa012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffcb4ed1baba3a1eb2171e00ddec8e5b72b346dd8c07f9c2b0d122d0d06bc92ea7000000006c493046022100a9b617843b68c284715d3e02fd120479cd0d96a6c43bf01e697fb0a460a21a3a022100ba0a12fbe8b993d4e7911fa3467615765dbe421ddf5c51b57a9c1ee19dcc00ba012103e633b4fa4ceb705c2da712390767199be8ef2448b3095dc01652e11b2b751505ffffffffc1b37ae964f605978022f94ce2f3f676d66a46d1aef7c2c17d6315b9697f2f75010000006a473044022079bd62ee09621a3be96b760c39e8ef78170101d46313923c6b07ae60a95c90670220238e51ea29fc70b04b65508450523caedbb11cb4dd5aa608c81487de798925ba0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffffedd005dc7790ef65c206abd1ab718e75252a40f4b1310e4102cd692eca9cacb0d10000006b48304502207722d6f9038673c86a1019b1c4de2d687ae246477cd4ca7002762be0299de385022100e594a11e3a313942595f7666dcf7078bcb14f1330f4206b95c917e7ec0e82fac012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffdf28d6e26fb7a85a1e6a229b972c1bae0edc1c11cb9ca51e4caf5e59fbea35a1000000006b483045022100a63a4788027b79b65c6f9d9e054f68cf3b4eed19efd82a2d53f70dcbe64683390220526f243671425b2bd05745fcf2729361f985cfe84ea80c7cfc817b93d8134374012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffffae2a2320a1582faa24469eff3024a6b98bfe00eb4f554d8a0b1421ba53bfd6a5010000006c493046022100b200ac6db16842f76dab9abe807ce423c992805879bc50abd46ed8275a59d9cf022100c0d518e85dd345b3c29dd4dc47b9a420d3ce817b18720e94966d2fe23413a408012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffffb3cc5a12548aa1794b4d2bbf076838cfd7fbafb7716da51ee8221a4ff19c291b000000006b483045022100ededc441c3103a6f2bd6cab7639421af0f6ec5e60503bce1e603cf34f00aee1c02205cb75f3f519a13fb348783b21db3085cb5ec7552c59e394fdbc3e1feea43f967012103a621f08be22d1bbdcbe4e527ee4927006aa555fc65e2aafa767d4ea2fe9dfa52ffffffff85145367313888d2cf2747274a32e20b2df074027bafd6f970003fcbcdf11d07150000006b483045022100d9eed5413d2a4b4b98625aa6e3169edc4fb4663e7862316d69224454e70cd8ca022061e506521d5ced51dd0ea36496e75904d756a4c4f9fb111568555075d5f68d9a012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff8292c11f6d35abab5bac3ebb627a4ff949e8ecd62d33ed137adf7aeb00e512b0090000006b48304502207e84b27139c4c19c828cb1e30c349bba88e4d9b59be97286960793b5ddc0a2af0221008cdc7a951e7f31c20953ed5635fbabf228e80b7047f32faaa0313e7693005177012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff883dcf9a86063db088ad064d0953258d4b0ff3425857402d2f3f839cee0f84581e0000006a4730440220426540dfed9c4ab5812e5f06df705b8bcf307dd7d20f7fa6512298b2a6314f420220064055096e3ca62f6c7352c66a5447767c53f946acdf35025ab3807ddb2fa404012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff6697dbb3ed98afe481b568459fa67e503f8a4254532465a670e54669d19c9fe6720000006a47304402200a5e673996f2fc88e21cc8613611f08a650bc0370338803591d85d0ec5663764022040b6664a0d1ec83a7f01975b8fde5232992b8ca58bf48af6725d2f92a936ab2e012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff023ffc2182517e1d3fa0896c5b0bd7b4d2ef8a1e42655abe2ced54f657125d59670000006c493046022100d93b30219c5735f673be5c3b4688366d96f545561c74cb62c6958c00f6960806022100ec8200adcb028f2184fa2a4f6faac7f8bb57cb4503bb7584ac11051fece31b3d012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff16f8c77166b0df3d7cc8b5b2ce825afbea9309ad7acd8e2461a255958f81fc06010000006b483045022100a13934e68d3f5b22b130c4cb33f4da468cffc52323a47fbfbe06b64858162246022047081e0a70ff770e64a2e2d31e5d520d9102268b57a47009a72fe73ec766901801210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff197b96f3c87a3adfaa17f63fddc2a738a690ca665439f9431dbbd655816c41fb000000006c49304602210097f1f35d5bdc1a3a60390a1b015b8e7c4f916aa3847aafd969e04975e15bbe70022100a9052eb25517d481f1fda1b129eb1b534da50ea1a51f3ee012dca3601c11b86a0121027a759be8df971a6a04fafcb4f6babf75dc811c5cdaa0734cddbe9b942ce75b34ffffffff20d9a261ee27aa1bd92e7db2fdca935909a40b648e974cd24a10d63b68b94039dd0000006b483045022012b3138c591bf7154b6fef457f2c4a3c7162225003788ac0024a99355865ff13022100b71b125ae1ffb2e1d1571f580cd3ebc8cd049a2d7a8a41f138ba94aeb982106f012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff50f179d5d16cd872f9a63c26c448464ae9bd95cd9421c0476113b5d314571b71010000006b483045022100f834ccc8b22ee72712a3e5e6ef4acb8b2fb791b5385b70e2cd4332674d6667f4022024fbda0a997e0c253503f217501f508a4d56edce2c813ecdd9ad796dbeba907401210234b9d9413f247bb78cd3293b7b65a2c38018ba5621ea9ee737f3a6a3523fb4cdffffffff551b865d1568ac0a305e5f9c5dae6c540982334efbe789074318e0efc5b564631b0000006b48304502203b2fd1e39ae0e469d7a15768f262661b0de41470daf0fe8c4fd0c26542a0870002210081c57e331f9a2d214457d953e3542904727ee412c63028113635d7224da3dccc012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff57503e5a016189d407a721791459280875264f908ca2c5d4862c01386e7fb50b470400006b48304502206947a9c54f0664ece4430fd4ae999891dc50bb6126bc36b6a15a3189f29d25e9022100a86cfc4e2fdd9e39a20e305cfd1b76509c67b3e313e0f118229105caa0e823c9012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff3f16c1fb9d3e1a26d872933e955df85ee7f3f817711062b00b54a2144827349b250000006b483045022100c7128fe10b2d38744ae8177776054c29fc8ec13f07207723e70766ab7164847402201d2cf09009b9596de74c0183d1ab832e5edddb7a9965880bb400097e850850f8012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff4142a69d85b8498af214f0dd427b6ab29c240a0b8577e2944d37a7d8c05c6bb8140000006b48304502203b89a71628a28cc3703d170ca3be77786cff6b867e38a18b719705f8a326578f022100b2a9879e1acf621faa6466c207746a7f3eb4c8514c1482969aba3f2a957f1321012103f1575d6124ac78be398c25b31146d08313c6072d23a4d7df5ac6a9f87346c64cffffffff36e2feecc0a4bff7480015d42c12121932db389025ed0ac1d344ecee53230a3df20000006c493046022100ef794a8ef7fd6752d2a183c18866ff6e8dc0f5bd889a63e2c21cf303a6302461022100c1b09662d9e92988c3f9fcf17d1bcc79b5403647095d7212b9f8a1278a532d68012103091137f3ef23f4acfc19a5953a68b2074fae942ad3563ef28c33b0cac9a93adcffffffff0260f73608000000001976a9148fd139bb39ced713f231c58a4d07bf6954d1c20188ac41420f00000000001976a9146c772e9cf96371bba3da8cb733da70a2fcf2007888ac00000000
diff --git a/src/test/data/txcreate1.hex b/src/test/data/txcreate1.hex
new file mode 100644
index 0000000000..e2981a51c9
--- /dev/null
+++ b/src/test/data/txcreate1.hex
@@ -0,0 +1 @@
+01000000031f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff7cca453133921c50d5025878f7f738d1df891fd359763331935784cf6b9c82bf1200000000fffffffffccd319e04a996c96cfc0bf4c07539aa90bd0b1a700ef72fae535d6504f9a6220100000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d717000000001976a914f2d4db28cad6502226ee484ae24505c2885cb12d88ac00000000
diff --git a/src/test/hash_tests.cpp b/src/test/hash_tests.cpp
index 4568c8769b..b8e290f071 100644
--- a/src/test/hash_tests.cpp
+++ b/src/test/hash_tests.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "hash.h"
-#include "util.h"
+#include "utilstrencodings.h"
#include <vector>
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 107c0f06e7..d5475a92bf 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -110,14 +110,14 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign)
BOOST_AUTO_TEST_CASE(rpc_format_monetary_values)
{
- BOOST_CHECK(write_string(ValueFromAmount(0LL), false) == "0.00000000");
- BOOST_CHECK(write_string(ValueFromAmount(1LL), false) == "0.00000001");
- BOOST_CHECK(write_string(ValueFromAmount(17622195LL), false) == "0.17622195");
- BOOST_CHECK(write_string(ValueFromAmount(50000000LL), false) == "0.50000000");
- BOOST_CHECK(write_string(ValueFromAmount(89898989LL), false) == "0.89898989");
- BOOST_CHECK(write_string(ValueFromAmount(100000000LL), false) == "1.00000000");
- BOOST_CHECK(write_string(ValueFromAmount(2099999999999990LL), false) == "20999999.99999990");
- BOOST_CHECK(write_string(ValueFromAmount(2099999999999999LL), false) == "20999999.99999999");
+ BOOST_CHECK_EQUAL(write_string(ValueFromAmount(0LL), false), "0.00000000");
+ BOOST_CHECK_EQUAL(write_string(ValueFromAmount(1LL), false), "0.00000001");
+ BOOST_CHECK_EQUAL(write_string(ValueFromAmount(17622195LL), false), "0.17622195");
+ BOOST_CHECK_EQUAL(write_string(ValueFromAmount(50000000LL), false), "0.50000000");
+ BOOST_CHECK_EQUAL(write_string(ValueFromAmount(89898989LL), false), "0.89898989");
+ BOOST_CHECK_EQUAL(write_string(ValueFromAmount(100000000LL), false), "1.00000000");
+ BOOST_CHECK_EQUAL(write_string(ValueFromAmount(2099999999999990LL), false), "20999999.99999990");
+ BOOST_CHECK_EQUAL(write_string(ValueFromAmount(2099999999999999LL), false), "20999999.99999999");
}
static Value ValueFromString(const std::string &str)
@@ -129,14 +129,14 @@ static Value ValueFromString(const std::string &str)
BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
{
- BOOST_CHECK(AmountFromValue(ValueFromString("0.00000001")) == 1LL);
- BOOST_CHECK(AmountFromValue(ValueFromString("0.17622195")) == 17622195LL);
- BOOST_CHECK(AmountFromValue(ValueFromString("0.5")) == 50000000LL);
- BOOST_CHECK(AmountFromValue(ValueFromString("0.50000000")) == 50000000LL);
- BOOST_CHECK(AmountFromValue(ValueFromString("0.89898989")) == 89898989LL);
- BOOST_CHECK(AmountFromValue(ValueFromString("1.00000000")) == 100000000LL);
- BOOST_CHECK(AmountFromValue(ValueFromString("20999999.9999999")) == 2099999999999990LL);
- BOOST_CHECK(AmountFromValue(ValueFromString("20999999.99999999")) == 2099999999999999LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001")), 1LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.17622195")), 17622195LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.5")), 50000000LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.50000000")), 50000000LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.89898989")), 89898989LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("1.00000000")), 100000000LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.9999999")), 2099999999999990LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.99999999")), 2099999999999999LL);
}
BOOST_AUTO_TEST_CASE(rpc_boostasiotocnetaddr)
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index bc9f31c077..77c44501ab 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -394,4 +394,15 @@ BOOST_AUTO_TEST_CASE(script_standard_push)
}
}
+BOOST_AUTO_TEST_CASE(script_IsPushOnly_on_invalid_scripts)
+{
+ // IsPushOnly returns false when given a script containing only pushes that
+ // are invalid due to truncation. IsPushOnly() is consensus critical
+ // because P2SH evaluation uses it, although this specific behavior should
+ // not be consensus critical as the P2SH evaluation would fail first due to
+ // the invalid push. Still, it doesn't hurt to test it explicitly.
+ static const unsigned char direct[] = { 1 };
+ BOOST_CHECK(!CScript(direct, direct+sizeof(direct)).IsPushOnly());
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 443b5853b2..68fad8d038 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -16,6 +16,7 @@
#include <boost/filesystem.hpp>
#include <boost/test/unit_test.hpp>
+#include <boost/thread.hpp>
CClientUIInterface uiInterface;
CWallet* pwalletMain;
diff --git a/src/test/timedata_tests.cpp b/src/test/timedata_tests.cpp
new file mode 100644
index 0000000000..aa4fa0d500
--- /dev/null
+++ b/src/test/timedata_tests.cpp
@@ -0,0 +1,38 @@
+// Copyright (c) 2011-2014 The Bitcoin Core developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+//
+#include "timedata.h"
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+
+BOOST_AUTO_TEST_SUITE(timedata_tests)
+
+BOOST_AUTO_TEST_CASE(util_MedianFilter)
+{
+ CMedianFilter<int> filter(5, 15);
+
+ BOOST_CHECK_EQUAL(filter.median(), 15);
+
+ filter.input(20); // [15 20]
+ BOOST_CHECK_EQUAL(filter.median(), 17);
+
+ filter.input(30); // [15 20 30]
+ BOOST_CHECK_EQUAL(filter.median(), 20);
+
+ filter.input(3); // [3 15 20 30]
+ BOOST_CHECK_EQUAL(filter.median(), 17);
+
+ filter.input(7); // [3 7 15 20 30]
+ BOOST_CHECK_EQUAL(filter.median(), 15);
+
+ filter.input(18); // [3 7 18 20 30]
+ BOOST_CHECK_EQUAL(filter.median(), 18);
+
+ filter.input(0); // [0 3 7 18 30]
+ BOOST_CHECK_EQUAL(filter.median(), 7);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp
new file mode 100644
index 0000000000..23bc5f6b12
--- /dev/null
+++ b/src/test/univalue_tests.cpp
@@ -0,0 +1,275 @@
+// Copyright 2014 BitPay, Inc.
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include <stdint.h>
+#include <vector>
+#include <string>
+#include <map>
+#include "univalue/univalue.h"
+
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+
+BOOST_AUTO_TEST_SUITE(univalue_tests)
+
+BOOST_AUTO_TEST_CASE(univalue_constructor)
+{
+ UniValue v1;
+ BOOST_CHECK(v1.isNull());
+
+ UniValue v2(UniValue::VSTR);
+ BOOST_CHECK(v2.isStr());
+
+ UniValue v3(UniValue::VSTR, "foo");
+ BOOST_CHECK(v3.isStr());
+ BOOST_CHECK_EQUAL(v3.getValStr(), "foo");
+
+ UniValue numTest;
+ BOOST_CHECK(numTest.setNumStr("82"));
+ BOOST_CHECK(numTest.isNum());
+ BOOST_CHECK_EQUAL(numTest.getValStr(), "82");
+
+ uint64_t vu64 = 82;
+ UniValue v4(vu64);
+ BOOST_CHECK(v4.isNum());
+ BOOST_CHECK_EQUAL(v4.getValStr(), "82");
+
+ int64_t vi64 = -82;
+ UniValue v5(vi64);
+ BOOST_CHECK(v5.isNum());
+ BOOST_CHECK_EQUAL(v5.getValStr(), "-82");
+
+ int vi = -688;
+ UniValue v6(vi);
+ BOOST_CHECK(v6.isNum());
+ BOOST_CHECK_EQUAL(v6.getValStr(), "-688");
+
+ double vd = -7.21;
+ UniValue v7(vd);
+ BOOST_CHECK(v7.isNum());
+ BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21");
+
+ string vs("yawn");
+ UniValue v8(vs);
+ BOOST_CHECK(v8.isStr());
+ BOOST_CHECK_EQUAL(v8.getValStr(), "yawn");
+
+ const char *vcs = "zappa";
+ UniValue v9(vcs);
+ BOOST_CHECK(v9.isStr());
+ BOOST_CHECK_EQUAL(v9.getValStr(), "zappa");
+}
+
+BOOST_AUTO_TEST_CASE(univalue_set)
+{
+ UniValue v(UniValue::VSTR, "foo");
+ v.clear();
+ BOOST_CHECK(v.isNull());
+ BOOST_CHECK_EQUAL(v.getValStr(), "");
+
+ BOOST_CHECK(v.setObject());
+ BOOST_CHECK(v.isObject());
+ BOOST_CHECK_EQUAL(v.count(), 0);
+ BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ);
+ BOOST_CHECK(v.empty());
+
+ BOOST_CHECK(v.setArray());
+ BOOST_CHECK(v.isArray());
+ BOOST_CHECK_EQUAL(v.count(), 0);
+
+ BOOST_CHECK(v.setStr("zum"));
+ BOOST_CHECK(v.isStr());
+ BOOST_CHECK_EQUAL(v.getValStr(), "zum");
+
+ BOOST_CHECK(v.setFloat(-1.01));
+ BOOST_CHECK(v.isNum());
+ BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
+
+ BOOST_CHECK(v.setInt((int)1023));
+ BOOST_CHECK(v.isNum());
+ BOOST_CHECK_EQUAL(v.getValStr(), "1023");
+
+ BOOST_CHECK(v.setInt((int64_t)-1023LL));
+ BOOST_CHECK(v.isNum());
+ BOOST_CHECK_EQUAL(v.getValStr(), "-1023");
+
+ BOOST_CHECK(v.setInt((uint64_t)1023ULL));
+ BOOST_CHECK(v.isNum());
+ BOOST_CHECK_EQUAL(v.getValStr(), "1023");
+
+ BOOST_CHECK(v.setNumStr("-688"));
+ BOOST_CHECK(v.isNum());
+ BOOST_CHECK_EQUAL(v.getValStr(), "-688");
+
+ BOOST_CHECK(v.setBool(false));
+ BOOST_CHECK_EQUAL(v.isBool(), true);
+ BOOST_CHECK_EQUAL(v.isTrue(), false);
+ BOOST_CHECK_EQUAL(v.isFalse(), true);
+ BOOST_CHECK_EQUAL(v.getBool(), false);
+
+ BOOST_CHECK(v.setBool(true));
+ BOOST_CHECK_EQUAL(v.isBool(), true);
+ BOOST_CHECK_EQUAL(v.isTrue(), true);
+ BOOST_CHECK_EQUAL(v.isFalse(), false);
+ BOOST_CHECK_EQUAL(v.getBool(), true);
+
+ BOOST_CHECK(!v.setNumStr("zombocom"));
+
+ BOOST_CHECK(v.setNull());
+ BOOST_CHECK(v.isNull());
+}
+
+BOOST_AUTO_TEST_CASE(univalue_array)
+{
+ UniValue arr(UniValue::VARR);
+
+ UniValue v((int64_t)1023LL);
+ BOOST_CHECK(arr.push_back(v));
+
+ string vStr("zippy");
+ BOOST_CHECK(arr.push_back(vStr));
+
+ const char *s = "pippy";
+ BOOST_CHECK(arr.push_back(s));
+
+ vector<UniValue> vec;
+ v.setStr("boing");
+ vec.push_back(v);
+
+ v.setStr("going");
+ vec.push_back(v);
+
+ BOOST_CHECK(arr.push_backV(vec));
+
+ BOOST_CHECK_EQUAL(arr.empty(), false);
+ BOOST_CHECK_EQUAL(arr.count(), 5);
+
+ BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023");
+ BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy");
+ BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy");
+ BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing");
+ BOOST_CHECK_EQUAL(arr[4].getValStr(), "going");
+
+ BOOST_CHECK_EQUAL(arr[999].getValStr(), "");
+
+ arr.clear();
+ BOOST_CHECK(arr.empty());
+ BOOST_CHECK_EQUAL(arr.count(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(univalue_object)
+{
+ UniValue obj(UniValue::VOBJ);
+ string strKey, strVal;
+ UniValue v;
+
+ strKey = "age";
+ v.setInt(100);
+ BOOST_CHECK(obj.pushKV(strKey, v));
+
+ strKey = "first";
+ strVal = "John";
+ BOOST_CHECK(obj.pushKV(strKey, strVal));
+
+ strKey = "last";
+ const char *cVal = "Smith";
+ BOOST_CHECK(obj.pushKV(strKey, cVal));
+
+ strKey = "distance";
+ BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25));
+
+ strKey = "time";
+ BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600));
+
+ strKey = "calories";
+ BOOST_CHECK(obj.pushKV(strKey, (int) 12));
+
+ strKey = "temperature";
+ BOOST_CHECK(obj.pushKV(strKey, (double) 90.012));
+
+ UniValue obj2(UniValue::VOBJ);
+ BOOST_CHECK(obj2.pushKV("cat1", 9000));
+ BOOST_CHECK(obj2.pushKV("cat2", 12345));
+
+ BOOST_CHECK(obj.pushKVs(obj2));
+
+ BOOST_CHECK_EQUAL(obj.empty(), false);
+ BOOST_CHECK_EQUAL(obj.count(), 9);
+
+ BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100");
+ BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John");
+ BOOST_CHECK_EQUAL(obj["last"].getValStr(), "Smith");
+ BOOST_CHECK_EQUAL(obj["distance"].getValStr(), "25");
+ BOOST_CHECK_EQUAL(obj["time"].getValStr(), "3600");
+ BOOST_CHECK_EQUAL(obj["calories"].getValStr(), "12");
+ BOOST_CHECK_EQUAL(obj["temperature"].getValStr(), "90.012");
+ BOOST_CHECK_EQUAL(obj["cat1"].getValStr(), "9000");
+ BOOST_CHECK_EQUAL(obj["cat2"].getValStr(), "12345");
+
+ BOOST_CHECK_EQUAL(obj["nyuknyuknyuk"].getValStr(), "");
+
+ BOOST_CHECK(obj.exists("age"));
+ BOOST_CHECK(obj.exists("first"));
+ BOOST_CHECK(obj.exists("last"));
+ BOOST_CHECK(obj.exists("distance"));
+ BOOST_CHECK(obj.exists("time"));
+ BOOST_CHECK(obj.exists("calories"));
+ BOOST_CHECK(obj.exists("temperature"));
+ BOOST_CHECK(obj.exists("cat1"));
+ BOOST_CHECK(obj.exists("cat2"));
+
+ BOOST_CHECK(!obj.exists("nyuknyuknyuk"));
+
+ map<string, UniValue::VType> objTypes;
+ objTypes["age"] = UniValue::VNUM;
+ objTypes["first"] = UniValue::VSTR;
+ objTypes["last"] = UniValue::VSTR;
+ objTypes["distance"] = UniValue::VNUM;
+ objTypes["time"] = UniValue::VNUM;
+ objTypes["calories"] = UniValue::VNUM;
+ objTypes["temperature"] = UniValue::VNUM;
+ objTypes["cat1"] = UniValue::VNUM;
+ objTypes["cat2"] = UniValue::VNUM;
+ BOOST_CHECK(obj.checkObject(objTypes));
+
+ objTypes["cat2"] = UniValue::VSTR;
+ BOOST_CHECK(!obj.checkObject(objTypes));
+
+ obj.clear();
+ BOOST_CHECK(obj.empty());
+ BOOST_CHECK_EQUAL(obj.count(), 0);
+}
+
+static const char *json1 =
+"[1.1,{\"key1\":\"str\",\"key2\":800,\"key3\":{\"name\":\"martian\"}}]";
+
+BOOST_AUTO_TEST_CASE(univalue_readwrite)
+{
+ UniValue v;
+ BOOST_CHECK(v.read(json1));
+
+ string strJson1(json1);
+ BOOST_CHECK(v.read(strJson1));
+
+ BOOST_CHECK(v.isArray());
+ BOOST_CHECK_EQUAL(v.count(), 2);
+
+ BOOST_CHECK_EQUAL(v[0].getValStr(), "1.1");
+
+ UniValue obj = v[1];
+ BOOST_CHECK(obj.isObject());
+ BOOST_CHECK_EQUAL(obj.count(), 3);
+
+ BOOST_CHECK(obj["key1"].isStr());
+ BOOST_CHECK_EQUAL(obj["key1"].getValStr(), "str");
+ BOOST_CHECK(obj["key2"].isNum());
+ BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800");
+ BOOST_CHECK(obj["key3"].isObject());
+
+ BOOST_CHECK_EQUAL(strJson1, v.write());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 068b9f29c8..e077c9de3b 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -4,8 +4,11 @@
#include "util.h"
+#include "core.h"
#include "random.h"
#include "sync.h"
+#include "utilstrencodings.h"
+#include "utilmoneystr.h"
#include <stdint.h>
#include <vector>
@@ -36,31 +39,6 @@ BOOST_AUTO_TEST_CASE(util_criticalsection)
} while(0);
}
-BOOST_AUTO_TEST_CASE(util_MedianFilter)
-{
- CMedianFilter<int> filter(5, 15);
-
- BOOST_CHECK_EQUAL(filter.median(), 15);
-
- filter.input(20); // [15 20]
- BOOST_CHECK_EQUAL(filter.median(), 17);
-
- filter.input(30); // [15 20 30]
- BOOST_CHECK_EQUAL(filter.median(), 20);
-
- filter.input(3); // [3 15 20 30]
- BOOST_CHECK_EQUAL(filter.median(), 17);
-
- filter.input(7); // [3 7 15 20 30]
- BOOST_CHECK_EQUAL(filter.median(), 15);
-
- filter.input(18); // [3 7 18 20 30]
- BOOST_CHECK_EQUAL(filter.median(), 18);
-
- filter.input(0); // [0 3 7 18 30]
- BOOST_CHECK_EQUAL(filter.median(), 7);
-}
-
static const unsigned char ParseHex_expected[65] = {
0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7,
0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde,
diff --git a/src/timedata.cpp b/src/timedata.cpp
index 4576786b96..40cdb33f7a 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -8,6 +8,7 @@
#include "sync.h"
#include "ui_interface.h"
#include "util.h"
+#include "utilstrencodings.h"
#include <boost/foreach.hpp>
@@ -35,6 +36,11 @@ int64_t GetAdjustedTime()
return GetTime() + GetTimeOffset();
}
+static int64_t abs64(int64_t n)
+{
+ return (n >= 0 ? n : -n);
+}
+
void AddTimeData(const CNetAddr& ip, int64_t nTime)
{
int64_t nOffsetSample = nTime - GetTime();
diff --git a/src/timedata.h b/src/timedata.h
index 0e7bdc2c1f..d0c84b3183 100644
--- a/src/timedata.h
+++ b/src/timedata.h
@@ -6,9 +6,68 @@
#define BITCOIN_TIMEDATA_H
#include <stdint.h>
+#include <vector>
+#include <algorithm>
+#include <assert.h>
class CNetAddr;
+/** Median filter over a stream of values.
+ * Returns the median of the last N numbers
+ */
+template <typename T> class CMedianFilter
+{
+private:
+ std::vector<T> vValues;
+ std::vector<T> vSorted;
+ unsigned int nSize;
+public:
+ CMedianFilter(unsigned int size, T initial_value):
+ nSize(size)
+ {
+ vValues.reserve(size);
+ vValues.push_back(initial_value);
+ vSorted = vValues;
+ }
+
+ void input(T value)
+ {
+ if(vValues.size() == nSize)
+ {
+ vValues.erase(vValues.begin());
+ }
+ vValues.push_back(value);
+
+ vSorted.resize(vValues.size());
+ std::copy(vValues.begin(), vValues.end(), vSorted.begin());
+ std::sort(vSorted.begin(), vSorted.end());
+ }
+
+ T median() const
+ {
+ int size = vSorted.size();
+ assert(size>0);
+ if(size & 1) // Odd number of elements
+ {
+ return vSorted[size/2];
+ }
+ else // Even number of elements
+ {
+ return (vSorted[size/2-1] + vSorted[size/2]) / 2;
+ }
+ }
+
+ int size() const
+ {
+ return vValues.size();
+ }
+
+ std::vector<T> sorted () const
+ {
+ return vSorted;
+ }
+};
+
/* Functions to keep track of adjusted P2P time */
int64_t GetTimeOffset();
int64_t GetAdjustedTime();
diff --git a/src/tinyformat.h b/src/tinyformat.h
index b6113029f5..73d49a1fe4 100644
--- a/src/tinyformat.h
+++ b/src/tinyformat.h
@@ -121,6 +121,7 @@ namespace tfm = tinyformat;
#include <cassert>
#include <iostream>
#include <sstream>
+#include <stdexcept>
#ifndef TINYFORMAT_ERROR
# define TINYFORMAT_ERROR(reason) assert(0 && reason)
@@ -1007,4 +1008,6 @@ TINYFORMAT_WRAP_FORMAT_N(16, returnType, funcName, funcDeclSuffix, bodyPrefix, s
} // namespace tinyformat
+#define strprintf tfm::format
+
#endif // TINYFORMAT_H_INCLUDED
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 52cd96283e..d4c6007558 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -9,6 +9,7 @@
#include "pow.h"
#include "uint256.h"
+#include <boost/thread.hpp>
#include <stdint.h>
using namespace std;
@@ -27,7 +28,7 @@ void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) {
CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe) {
}
-bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) {
+bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const {
return db.Read(make_pair('c', txid), coins);
}
@@ -37,11 +38,11 @@ bool CCoinsViewDB::SetCoins(const uint256 &txid, const CCoins &coins) {
return db.WriteBatch(batch);
}
-bool CCoinsViewDB::HaveCoins(const uint256 &txid) {
+bool CCoinsViewDB::HaveCoins(const uint256 &txid) const {
return db.Exists(make_pair('c', txid));
}
-uint256 CCoinsViewDB::GetBestBlock() {
+uint256 CCoinsViewDB::GetBestBlock() const {
uint256 hashBestChain;
if (!db.Read('B', hashBestChain))
return uint256(0);
@@ -54,12 +55,15 @@ bool CCoinsViewDB::SetBestBlock(const uint256 &hashBlock) {
return db.WriteBatch(batch);
}
-bool CCoinsViewDB::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock) {
+bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
LogPrint("coindb", "Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size());
CLevelDBBatch batch;
- for (CCoinsMap::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++)
+ for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
BatchWriteCoins(batch, it->first, it->second);
+ CCoinsMap::iterator itOld = it++;
+ mapCoins.erase(itOld);
+ }
if (hashBlock != uint256(0))
BatchWriteHashBestChain(batch, hashBlock);
@@ -102,8 +106,11 @@ bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
return Read('l', nFile);
}
-bool CCoinsViewDB::GetStats(CCoinsStats &stats) {
- leveldb::Iterator *pcursor = db.NewIterator();
+bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
+ /* It seems that there are no "const iterators" for LevelDB. Since we
+ only need read operations on it, use a const-cast to get around
+ that restriction. */
+ leveldb::Iterator *pcursor = const_cast<CLevelDBWrapper*>(&db)->NewIterator();
pcursor->SeekToFirst();
CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
@@ -146,7 +153,6 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) {
return error("%s : Deserialize or I/O error - %s", __func__, e.what());
}
}
- delete pcursor;
stats.nHeight = mapBlockIndex.find(GetBestBlock())->second->nHeight;
stats.hashSerialized = ss.GetHash();
stats.nTotalAmount = nTotalAmount;
@@ -178,7 +184,7 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
bool CBlockTreeDB::LoadBlockIndexGuts()
{
- leveldb::Iterator *pcursor = NewIterator();
+ boost::scoped_ptr<leveldb::Iterator> pcursor(NewIterator());
CDataStream ssKeySet(SER_DISK, CLIENT_VERSION);
ssKeySet << make_pair('b', uint256(0));
@@ -224,7 +230,6 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
return error("%s : Deserialize or I/O error - %s", __func__, e.what());
}
}
- delete pcursor;
return true;
}
diff --git a/src/txdb.h b/src/txdb.h
index 7d670c2542..f0b6b9e1dd 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -32,13 +32,13 @@ protected:
public:
CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
- bool GetCoins(const uint256 &txid, CCoins &coins);
+ bool GetCoins(const uint256 &txid, CCoins &coins) const;
bool SetCoins(const uint256 &txid, const CCoins &coins);
- bool HaveCoins(const uint256 &txid);
- uint256 GetBestBlock();
+ bool HaveCoins(const uint256 &txid) const;
+ uint256 GetBestBlock() const;
bool SetBestBlock(const uint256 &hashBlock);
- bool BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock);
- bool GetStats(CCoinsStats &stats);
+ bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock);
+ bool GetStats(CCoinsStats &stats) const;
};
/** Access to the block database (blocks/index/) */
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 29924fff09..8af1f1c91b 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -5,6 +5,7 @@
#include "core.h"
#include "txmempool.h"
+#include "util.h"
#include <boost/circular_buffer.hpp>
@@ -402,6 +403,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry)
for (unsigned int i = 0; i < tx.vin.size(); i++)
mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i);
nTransactionsUpdated++;
+ totalTxSize += entry.GetTxSize();
}
return true;
}
@@ -426,6 +428,8 @@ void CTxMemPool::remove(const CTransaction &tx, std::list<CTransaction>& removed
removed.push_front(tx);
BOOST_FOREACH(const CTxIn& txin, tx.vin)
mapNextTx.erase(txin.prevout);
+
+ totalTxSize -= mapTx[hash].GetTxSize();
mapTx.erase(hash);
nTransactionsUpdated++;
}
@@ -477,19 +481,23 @@ void CTxMemPool::clear()
LOCK(cs);
mapTx.clear();
mapNextTx.clear();
+ totalTxSize = 0;
++nTransactionsUpdated;
}
-void CTxMemPool::check(CCoinsViewCache *pcoins) const
+void CTxMemPool::check(const CCoinsViewCache *pcoins) const
{
if (!fSanityCheck)
return;
LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size());
+ uint64_t checkTotal = 0;
+
LOCK(cs);
for (std::map<uint256, CTxMemPoolEntry>::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
unsigned int i = 0;
+ checkTotal += it->second.GetTxSize();
const CTransaction& tx = it->second.GetTx();
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
// Check that every mempool transaction's inputs refer to available coins, or other mempool tx's.
@@ -498,7 +506,7 @@ void CTxMemPool::check(CCoinsViewCache *pcoins) const
const CTransaction& tx2 = it2->second.GetTx();
assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull());
} else {
- CCoins &coins = pcoins->GetCoins(txin.prevout.hash);
+ const CCoins &coins = pcoins->GetCoins(txin.prevout.hash);
assert(coins.IsAvailable(txin.prevout.n));
}
// Check whether its inputs are marked in mapNextTx.
@@ -518,6 +526,8 @@ void CTxMemPool::check(CCoinsViewCache *pcoins) const
assert(tx.vin.size() > it->second.n);
assert(it->first == it->second.ptx->vin[it->second.n].prevout);
}
+
+ assert(totalTxSize == checkTotal);
}
void CTxMemPool::queryHashes(vector<uint256>& vtxid)
@@ -616,7 +626,7 @@ void CTxMemPool::ClearPrioritisation(const uint256 hash)
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
-bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) {
+bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const {
// If an entry in the mempool exists, always return that one, as it's guaranteed to never
// conflict with the underlying cache, and it cannot have pruned entries (as it contains full)
// transactions. First checking the underlying cache risks returning a pruned entry instead.
@@ -628,7 +638,7 @@ bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) {
return (base->GetCoins(txid, coins) && !coins.IsPruned());
}
-bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) {
+bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const {
return mempool.exists(txid) || base->HaveCoins(txid);
}
diff --git a/src/txmempool.h b/src/txmempool.h
index 41b2c52f39..d95c4d970b 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -68,6 +68,7 @@ private:
CMinerPolicyEstimator* minerPolicyEstimator;
CFeeRate minRelayFee; // Passed to constructor to avoid dependency on main
+ uint64_t totalTxSize; // sum of all mempool tx' byte sizes
public:
mutable CCriticalSection cs;
@@ -84,7 +85,7 @@ public:
* all inputs are in the mapNextTx array). If sanity-checking is turned off,
* check does nothing.
*/
- void check(CCoinsViewCache *pcoins) const;
+ void check(const CCoinsViewCache *pcoins) const;
void setSanityCheck(bool _fSanityCheck) { fSanityCheck = _fSanityCheck; }
bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry);
@@ -108,6 +109,11 @@ public:
LOCK(cs);
return mapTx.size();
}
+ uint64_t GetTotalTxSize()
+ {
+ LOCK(cs);
+ return totalTxSize;
+ }
bool exists(uint256 hash)
{
@@ -137,8 +143,8 @@ protected:
public:
CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn);
- bool GetCoins(const uint256 &txid, CCoins &coins);
- bool HaveCoins(const uint256 &txid);
+ bool GetCoins(const uint256 &txid, CCoins &coins) const;
+ bool HaveCoins(const uint256 &txid) const;
};
#endif /* BITCOIN_TXMEMPOOL_H */
diff --git a/src/uint256.cpp b/src/uint256.cpp
index 08c05594fd..feda0ca5a9 100644
--- a/src/uint256.cpp
+++ b/src/uint256.cpp
@@ -4,7 +4,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "uint256.h"
-#include "util.h"
+
+#include "utilstrencodings.h"
#include <stdio.h>
#include <string.h>
diff --git a/src/univalue/gen.cpp b/src/univalue/gen.cpp
new file mode 100644
index 0000000000..881948f46e
--- /dev/null
+++ b/src/univalue/gen.cpp
@@ -0,0 +1,78 @@
+// Copyright 2014 BitPay Inc.
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+//
+// To re-create univalue_escapes.h:
+// $ g++ -o gen gen.cpp
+// $ ./gen > univalue_escapes.h
+//
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include "univalue.h"
+
+using namespace std;
+
+static bool initEscapes;
+static const char *escapes[256];
+
+static void initJsonEscape()
+{
+ escapes[(int)'"'] = "\\\"";
+ escapes[(int)'\\'] = "\\\\";
+ escapes[(int)'/'] = "\\/";
+ escapes[(int)'\b'] = "\\b";
+ escapes[(int)'\f'] = "\\f";
+ escapes[(int)'\n'] = "\\n";
+ escapes[(int)'\r'] = "\\r";
+ escapes[(int)'\t'] = "\\t";
+
+ initEscapes = true;
+}
+
+static void outputEscape()
+{
+ printf( "// Automatically generated file. Do not modify.\n"
+ "#ifndef __UNIVALUE_ESCAPES_H__\n"
+ "#define __UNIVALUE_ESCAPES_H__\n"
+ "static const char *escapes[256] = {\n");
+
+ for (unsigned int i = 0; i < 256; i++) {
+ if (!escapes[i]) {
+ printf("\tNULL,\n");
+ } else {
+ printf("\t\"");
+
+ unsigned int si;
+ for (si = 0; si < strlen(escapes[i]); si++) {
+ char ch = escapes[i][si];
+ switch (ch) {
+ case '"':
+ printf("\\\"");
+ break;
+ case '\\':
+ printf("\\\\");
+ break;
+ default:
+ printf("%c", escapes[i][si]);
+ break;
+ }
+ }
+
+ printf("\",\n");
+ }
+ }
+
+ printf( "};\n"
+ "#endif // __UNIVALUE_ESCAPES_H__\n");
+}
+
+int main (int argc, char *argv[])
+{
+ initJsonEscape();
+ outputEscape();
+ return 0;
+}
+
diff --git a/src/univalue/univalue.cpp b/src/univalue/univalue.cpp
index afc208bffb..b0171e48c4 100644
--- a/src/univalue/univalue.cpp
+++ b/src/univalue/univalue.cpp
@@ -44,7 +44,7 @@ static bool validNumStr(const string& s)
bool UniValue::setNumStr(const string& val_)
{
- if (!validNumStr(val))
+ if (!validNumStr(val_))
return false;
clear();
diff --git a/src/univalue/univalue_escapes.h b/src/univalue/univalue_escapes.h
new file mode 100644
index 0000000000..1d3a70a968
--- /dev/null
+++ b/src/univalue/univalue_escapes.h
@@ -0,0 +1,262 @@
+// Automatically generated file. Do not modify.
+#ifndef __UNIVALUE_ESCAPES_H__
+#define __UNIVALUE_ESCAPES_H__
+static const char *escapes[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "\\b",
+ "\\t",
+ "\\n",
+ NULL,
+ "\\f",
+ "\\r",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "\\\"",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "\\/",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "\\\\",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+#endif // __UNIVALUE_ESCAPES_H__
diff --git a/src/univalue/univalue_write.cpp b/src/univalue/univalue_write.cpp
index 1818f5c6f9..042091a827 100644
--- a/src/univalue/univalue_write.cpp
+++ b/src/univalue/univalue_write.cpp
@@ -5,33 +5,14 @@
#include <ctype.h>
#include <stdio.h>
#include "univalue.h"
+#include "univalue_escapes.h"
// TODO: Using UTF8
using namespace std;
-static bool initEscapes;
-static const char *escapes[256];
-
-static void initJsonEscape()
-{
- escapes['"'] = "\\\"";
- escapes['\\'] = "\\\\";
- escapes['/'] = "\\/";
- escapes['\b'] = "\\b";
- escapes['\f'] = "\\f";
- escapes['\n'] = "\\n";
- escapes['\r'] = "\\r";
- escapes['\t'] = "\\t";
-
- initEscapes = true;
-}
-
static string json_escape(const string& inS)
{
- if (!initEscapes)
- initJsonEscape();
-
string outS;
outS.reserve(inS.size() * 2);
@@ -110,8 +91,11 @@ void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, s
if (prettyIndent)
s += indentStr(prettyIndent, indentLevel);
s += values[i].write(prettyIndent, indentLevel + 1);
- if (i != (values.size() - 1))
- s += ", ";
+ if (i != (values.size() - 1)) {
+ s += ",";
+ if (prettyIndent)
+ s += " ";
+ }
if (prettyIndent)
s += "\n";
}
@@ -130,7 +114,9 @@ void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel,
for (unsigned int i = 0; i < keys.size(); i++) {
if (prettyIndent)
s += indentStr(prettyIndent, indentLevel);
- s += "\"" + json_escape(keys[i]) + "\": ";
+ s += "\"" + json_escape(keys[i]) + "\":";
+ if (prettyIndent)
+ s += " ";
s += values[i].write(prettyIndent, indentLevel + 1);
if (i != (values.size() - 1))
s += ",";
diff --git a/src/util.cpp b/src/util.cpp
index d3fa5182f3..5a4e187f9e 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -3,30 +3,32 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#if defined(HAVE_CONFIG_H)
+#include "config/bitcoin-config.h"
+#endif
+
#include "util.h"
#include "chainparamsbase.h"
#include "random.h"
+#include "serialize.h"
#include "sync.h"
-#include "uint256.h"
-#include "version.h"
+#include "utilstrencodings.h"
+#include "utiltime.h"
#include <stdarg.h>
-#include <boost/date_time/posix_time/posix_time.hpp>
-
#ifndef WIN32
// for posix_fallocate
-#ifdef __linux_
+#ifdef __linux__
#ifdef _POSIX_C_SOURCE
#undef _POSIX_C_SOURCE
#endif
#define _POSIX_C_SOURCE 200112L
-#include <sys/prctl.h>
-#endif
+#endif // __linux__
#include <algorithm>
#include <fcntl.h>
@@ -61,6 +63,10 @@
#include <shlobj.h>
#endif
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
+
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
@@ -69,6 +75,7 @@
#include <boost/foreach.hpp>
#include <boost/program_options/detail/config_file.hpp>
#include <boost/program_options/parsers.hpp>
+#include <boost/thread.hpp>
#include <openssl/crypto.h>
#include <openssl/rand.h>
@@ -237,148 +244,6 @@ int LogPrintStr(const std::string &str)
return ret;
}
-string FormatMoney(int64_t n, bool fPlus)
-{
- // Note: not using straight sprintf here because we do NOT want
- // localized number formatting.
- int64_t n_abs = (n > 0 ? n : -n);
- int64_t quotient = n_abs/COIN;
- int64_t remainder = n_abs%COIN;
- string str = strprintf("%d.%08d", quotient, remainder);
-
- // Right-trim excess zeros before the decimal point:
- int nTrim = 0;
- for (int i = str.size()-1; (str[i] == '0' && isdigit(str[i-2])); --i)
- ++nTrim;
- if (nTrim)
- str.erase(str.size()-nTrim, nTrim);
-
- if (n < 0)
- str.insert((unsigned int)0, 1, '-');
- else if (fPlus && n > 0)
- str.insert((unsigned int)0, 1, '+');
- return str;
-}
-
-
-bool ParseMoney(const string& str, int64_t& nRet)
-{
- return ParseMoney(str.c_str(), nRet);
-}
-
-bool ParseMoney(const char* pszIn, int64_t& nRet)
-{
- string strWhole;
- int64_t nUnits = 0;
- const char* p = pszIn;
- while (isspace(*p))
- p++;
- for (; *p; p++)
- {
- if (*p == '.')
- {
- p++;
- int64_t nMult = CENT*10;
- while (isdigit(*p) && (nMult > 0))
- {
- nUnits += nMult * (*p++ - '0');
- nMult /= 10;
- }
- break;
- }
- if (isspace(*p))
- break;
- if (!isdigit(*p))
- return false;
- strWhole.insert(strWhole.end(), *p);
- }
- for (; *p; p++)
- if (!isspace(*p))
- return false;
- if (strWhole.size() > 10) // guard against 63 bit overflow
- return false;
- if (nUnits < 0 || nUnits > COIN)
- return false;
- int64_t nWhole = atoi64(strWhole);
- int64_t nValue = nWhole*COIN + nUnits;
-
- nRet = nValue;
- return true;
-}
-
-// safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything
-// even possibly remotely dangerous like & or >
-static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@");
-string SanitizeString(const string& str)
-{
- string strResult;
- for (std::string::size_type i = 0; i < str.size(); i++)
- {
- if (safeChars.find(str[i]) != std::string::npos)
- strResult.push_back(str[i]);
- }
- return strResult;
-}
-
-const signed char p_util_hexdigit[256] =
-{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
- -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
-
-signed char HexDigit(char c)
-{
- return p_util_hexdigit[(unsigned char)c];
-}
-
-bool IsHex(const string& str)
-{
- BOOST_FOREACH(char c, str)
- {
- if (HexDigit(c) < 0)
- return false;
- }
- return (str.size() > 0) && (str.size()%2 == 0);
-}
-
-vector<unsigned char> ParseHex(const char* psz)
-{
- // convert hex dump to vector
- vector<unsigned char> vch;
- while (true)
- {
- while (isspace(*psz))
- psz++;
- signed char c = HexDigit(*psz++);
- if (c == (signed char)-1)
- break;
- unsigned char n = (c << 4);
- c = HexDigit(*psz++);
- if (c == (signed char)-1)
- break;
- n |= c;
- vch.push_back(n);
- }
- return vch;
-}
-
-vector<unsigned char> ParseHex(const string& str)
-{
- return ParseHex(str.c_str());
-}
-
static void InterpretNegativeSetting(string name, map<string, string>& mapSettingsRet)
{
// interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
@@ -476,334 +341,6 @@ bool SoftSetBoolArg(const std::string& strArg, bool fValue)
return SoftSetArg(strArg, std::string("0"));
}
-
-string EncodeBase64(const unsigned char* pch, size_t len)
-{
- static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
- string strRet="";
- strRet.reserve((len+2)/3*4);
-
- int mode=0, left=0;
- const unsigned char *pchEnd = pch+len;
-
- while (pch<pchEnd)
- {
- int enc = *(pch++);
- switch (mode)
- {
- case 0: // we have no bits
- strRet += pbase64[enc >> 2];
- left = (enc & 3) << 4;
- mode = 1;
- break;
-
- case 1: // we have two bits
- strRet += pbase64[left | (enc >> 4)];
- left = (enc & 15) << 2;
- mode = 2;
- break;
-
- case 2: // we have four bits
- strRet += pbase64[left | (enc >> 6)];
- strRet += pbase64[enc & 63];
- mode = 0;
- break;
- }
- }
-
- if (mode)
- {
- strRet += pbase64[left];
- strRet += '=';
- if (mode == 1)
- strRet += '=';
- }
-
- return strRet;
-}
-
-string EncodeBase64(const string& str)
-{
- return EncodeBase64((const unsigned char*)str.c_str(), str.size());
-}
-
-vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
-{
- static const int decode64_table[256] =
- {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
- -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
- 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
- };
-
- if (pfInvalid)
- *pfInvalid = false;
-
- vector<unsigned char> vchRet;
- vchRet.reserve(strlen(p)*3/4);
-
- int mode = 0;
- int left = 0;
-
- while (1)
- {
- int dec = decode64_table[(unsigned char)*p];
- if (dec == -1) break;
- p++;
- switch (mode)
- {
- case 0: // we have no bits and get 6
- left = dec;
- mode = 1;
- break;
-
- case 1: // we have 6 bits and keep 4
- vchRet.push_back((left<<2) | (dec>>4));
- left = dec & 15;
- mode = 2;
- break;
-
- case 2: // we have 4 bits and get 6, we keep 2
- vchRet.push_back((left<<4) | (dec>>2));
- left = dec & 3;
- mode = 3;
- break;
-
- case 3: // we have 2 bits and get 6
- vchRet.push_back((left<<6) | dec);
- mode = 0;
- break;
- }
- }
-
- if (pfInvalid)
- switch (mode)
- {
- case 0: // 4n base64 characters processed: ok
- break;
-
- case 1: // 4n+1 base64 character processed: impossible
- *pfInvalid = true;
- break;
-
- case 2: // 4n+2 base64 characters processed: require '=='
- if (left || p[0] != '=' || p[1] != '=' || decode64_table[(unsigned char)p[2]] != -1)
- *pfInvalid = true;
- break;
-
- case 3: // 4n+3 base64 characters processed: require '='
- if (left || p[0] != '=' || decode64_table[(unsigned char)p[1]] != -1)
- *pfInvalid = true;
- break;
- }
-
- return vchRet;
-}
-
-string DecodeBase64(const string& str)
-{
- vector<unsigned char> vchRet = DecodeBase64(str.c_str());
- return string((const char*)&vchRet[0], vchRet.size());
-}
-
-string EncodeBase32(const unsigned char* pch, size_t len)
-{
- static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
-
- string strRet="";
- strRet.reserve((len+4)/5*8);
-
- int mode=0, left=0;
- const unsigned char *pchEnd = pch+len;
-
- while (pch<pchEnd)
- {
- int enc = *(pch++);
- switch (mode)
- {
- case 0: // we have no bits
- strRet += pbase32[enc >> 3];
- left = (enc & 7) << 2;
- mode = 1;
- break;
-
- case 1: // we have three bits
- strRet += pbase32[left | (enc >> 6)];
- strRet += pbase32[(enc >> 1) & 31];
- left = (enc & 1) << 4;
- mode = 2;
- break;
-
- case 2: // we have one bit
- strRet += pbase32[left | (enc >> 4)];
- left = (enc & 15) << 1;
- mode = 3;
- break;
-
- case 3: // we have four bits
- strRet += pbase32[left | (enc >> 7)];
- strRet += pbase32[(enc >> 2) & 31];
- left = (enc & 3) << 3;
- mode = 4;
- break;
-
- case 4: // we have two bits
- strRet += pbase32[left | (enc >> 5)];
- strRet += pbase32[enc & 31];
- mode = 0;
- }
- }
-
- static const int nPadding[5] = {0, 6, 4, 3, 1};
- if (mode)
- {
- strRet += pbase32[left];
- for (int n=0; n<nPadding[mode]; n++)
- strRet += '=';
- }
-
- return strRet;
-}
-
-string EncodeBase32(const string& str)
-{
- return EncodeBase32((const unsigned char*)str.c_str(), str.size());
-}
-
-vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid)
-{
- static const int decode32_table[256] =
- {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2,
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
- 23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
- };
-
- if (pfInvalid)
- *pfInvalid = false;
-
- vector<unsigned char> vchRet;
- vchRet.reserve((strlen(p))*5/8);
-
- int mode = 0;
- int left = 0;
-
- while (1)
- {
- int dec = decode32_table[(unsigned char)*p];
- if (dec == -1) break;
- p++;
- switch (mode)
- {
- case 0: // we have no bits and get 5
- left = dec;
- mode = 1;
- break;
-
- case 1: // we have 5 bits and keep 2
- vchRet.push_back((left<<3) | (dec>>2));
- left = dec & 3;
- mode = 2;
- break;
-
- case 2: // we have 2 bits and keep 7
- left = left << 5 | dec;
- mode = 3;
- break;
-
- case 3: // we have 7 bits and keep 4
- vchRet.push_back((left<<1) | (dec>>4));
- left = dec & 15;
- mode = 4;
- break;
-
- case 4: // we have 4 bits, and keep 1
- vchRet.push_back((left<<4) | (dec>>1));
- left = dec & 1;
- mode = 5;
- break;
-
- case 5: // we have 1 bit, and keep 6
- left = left << 5 | dec;
- mode = 6;
- break;
-
- case 6: // we have 6 bits, and keep 3
- vchRet.push_back((left<<2) | (dec>>3));
- left = dec & 7;
- mode = 7;
- break;
-
- case 7: // we have 3 bits, and keep 0
- vchRet.push_back((left<<5) | dec);
- mode = 0;
- break;
- }
- }
-
- if (pfInvalid)
- switch (mode)
- {
- case 0: // 8n base32 characters processed: ok
- break;
-
- case 1: // 8n+1 base32 characters processed: impossible
- case 3: // +3
- case 6: // +6
- *pfInvalid = true;
- break;
-
- case 2: // 8n+2 base32 characters processed: require '======'
- if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || p[4] != '=' || p[5] != '=' || decode32_table[(unsigned char)p[6]] != -1)
- *pfInvalid = true;
- break;
-
- case 4: // 8n+4 base32 characters processed: require '===='
- if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || decode32_table[(unsigned char)p[4]] != -1)
- *pfInvalid = true;
- break;
-
- case 5: // 8n+5 base32 characters processed: require '==='
- if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || decode32_table[(unsigned char)p[3]] != -1)
- *pfInvalid = true;
- break;
-
- case 7: // 8n+7 base32 characters processed: require '='
- if (left || p[0] != '=' || decode32_table[(unsigned char)p[1]] != -1)
- *pfInvalid = true;
- break;
- }
-
- return vchRet;
-}
-
-string DecodeBase32(const string& str)
-{
- vector<unsigned char> vchRet = DecodeBase32(str.c_str());
- return string((const char*)&vchRet[0], vchRet.size());
-}
-
static std::string FormatException(std::exception* pex, const char* pszThread)
{
#ifdef WIN32
@@ -1095,45 +632,6 @@ void ShrinkDebugFile()
fclose(file);
}
-static int64_t nMockTime = 0; // For unit testing
-
-int64_t GetTime()
-{
- if (nMockTime) return nMockTime;
-
- return time(NULL);
-}
-
-void SetMockTime(int64_t nMockTimeIn)
-{
- nMockTime = nMockTimeIn;
-}
-
-string FormatVersion(int nVersion)
-{
- if (nVersion%100 == 0)
- return strprintf("%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100);
- else
- return strprintf("%d.%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100, nVersion%100);
-}
-
-string FormatFullVersion()
-{
- return CLIENT_BUILD;
-}
-
-// Format the subversion field according to BIP 14 spec (https://en.bitcoin.it/wiki/BIP_0014)
-std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments)
-{
- std::ostringstream ss;
- ss << "/";
- ss << name << ":" << FormatVersion(nClientVersion);
- if (!comments.empty())
- ss << "(" << boost::algorithm::join(comments, "; ") << ")";
- ss << "/";
- return ss.str();
-}
-
#ifdef WIN32
boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate)
{
@@ -1204,20 +702,6 @@ void RenameThread(const char* name)
#endif
}
-bool ParseInt32(const std::string& str, int32_t *out)
-{
- char *endp = NULL;
- errno = 0; // strtol will not set errno if valid
- long int n = strtol(str.c_str(), &endp, 10);
- if(out) *out = (int)n;
- // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
- // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
- // platforms the size of these types may be different.
- return endp && *endp == 0 && !errno &&
- n >= std::numeric_limits<int32_t>::min() &&
- n <= std::numeric_limits<int32_t>::max();
-}
-
void SetupEnvironment()
{
#ifndef WIN32
@@ -1235,47 +719,15 @@ void SetupEnvironment()
#endif
}
-std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime)
+void SetThreadPriority(int nPriority)
{
- // std::locale takes ownership of the pointer
- std::locale loc(std::locale::classic(), new boost::posix_time::time_facet(pszFormat));
- std::stringstream ss;
- ss.imbue(loc);
- ss << boost::posix_time::from_time_t(nTime);
- return ss.str();
-}
-
-std::string FormatParagraph(const std::string in, size_t width, size_t indent)
-{
- std::stringstream out;
- size_t col = 0;
- size_t ptr = 0;
- while(ptr < in.size())
- {
- // Find beginning of next word
- ptr = in.find_first_not_of(' ', ptr);
- if (ptr == std::string::npos)
- break;
- // Find end of next word
- size_t endword = in.find_first_of(' ', ptr);
- if (endword == std::string::npos)
- endword = in.size();
- // Add newline and indentation if this wraps over the allowed width
- if (col > 0)
- {
- if ((col + endword - ptr) > width)
- {
- out << '\n';
- for(size_t i=0; i<indent; ++i)
- out << ' ';
- col = 0;
- } else
- out << ' ';
- }
- // Append word
- out << in.substr(ptr, endword - ptr);
- col += endword - ptr;
- ptr = endword;
- }
- return out.str();
+#ifdef WIN32
+ SetThreadPriority(GetCurrentThread(), nPriority);
+#else // WIN32
+#ifdef PRIO_THREAD
+ setpriority(PRIO_THREAD, 0, nPriority);
+#else // PRIO_THREAD
+ setpriority(PRIO_PROCESS, 0, nPriority);
+#endif // PRIO_THREAD
+#endif // WIN32
}
diff --git a/src/util.h b/src/util.h
index db2005337b..30f7c15c89 100644
--- a/src/util.h
+++ b/src/util.h
@@ -3,6 +3,10 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+/**
+ * Server/client environment: argument handling, config file parsing,
+ * logging, thread wrappers
+ */
#ifndef BITCOIN_UTIL_H
#define BITCOIN_UTIL_H
@@ -11,84 +15,17 @@
#endif
#include "compat.h"
-#include "serialize.h"
+#include "utiltime.h"
#include "tinyformat.h"
-#include <cstdio>
#include <exception>
#include <map>
-#include <stdarg.h>
#include <stdint.h>
#include <string>
-#include <utility>
#include <vector>
-#ifndef WIN32
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#endif
-
#include <boost/filesystem/path.hpp>
-#include <boost/thread.hpp>
-
-class uint256;
-
-static const int64_t COIN = 100000000;
-static const int64_t CENT = 1000000;
-
-#define BEGIN(a) ((char*)&(a))
-#define END(a) ((char*)&((&(a))[1]))
-#define UBEGIN(a) ((unsigned char*)&(a))
-#define UEND(a) ((unsigned char*)&((&(a))[1]))
-#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0]))
-
-// This is needed because the foreach macro can't get over the comma in pair<t1, t2>
-#define PAIRTYPE(t1, t2) std::pair<t1, t2>
-
-// Align by increasing pointer, must have extra space at end of buffer
-template <size_t nBytes, typename T>
-T* alignup(T* p)
-{
- union
- {
- T* ptr;
- size_t n;
- } u;
- u.ptr = p;
- u.n = (u.n + (nBytes-1)) & ~(nBytes-1);
- return u.ptr;
-}
-
-#ifdef WIN32
-#define MSG_DONTWAIT 0
-
-#ifndef S_IRUSR
-#define S_IRUSR 0400
-#define S_IWUSR 0200
-#endif
-#else
-#define MAX_PATH 1024
-#endif
-// As Solaris does not have the MSG_NOSIGNAL flag for send(2) syscall, it is defined as 0
-#if !defined(HAVE_MSG_NOSIGNAL) && !defined(MSG_NOSIGNAL)
-#define MSG_NOSIGNAL 0
-#endif
-
-inline void MilliSleep(int64_t n)
-{
-// Boost's sleep_for was uninterruptable when backed by nanosleep from 1.50
-// until fixed in 1.52. Use the deprecated sleep method for the broken case.
-// See: https://svn.boost.org/trac/boost/ticket/7238
-#if defined(HAVE_WORKING_BOOST_SLEEP_FOR)
- boost::this_thread::sleep_for(boost::chrono::milliseconds(n));
-#elif defined(HAVE_WORKING_BOOST_SLEEP)
- boost::this_thread::sleep(boost::posix_time::milliseconds(n));
-#else
-//should never get here
-#error missing boost sleep implementation
-#endif
-}
+#include <boost/thread/exceptions.hpp>
extern std::map<std::string, std::string> mapArgs;
extern std::map<std::string, std::vector<std::string> > mapMultiArgs;
@@ -108,7 +45,6 @@ bool LogAcceptCategory(const char* category);
/* Send a string to the log output */
int LogPrintStr(const std::string &str);
-#define strprintf tfm::format
#define LogPrintf(...) LogPrint(NULL, __VA_ARGS__)
/* When we switch to C++11, this can be switched to variadic templates instead
@@ -147,22 +83,6 @@ static inline bool error(const char* format)
}
void PrintExceptionContinue(std::exception* pex, const char* pszThread);
-std::string FormatMoney(int64_t n, bool fPlus=false);
-bool ParseMoney(const std::string& str, int64_t& nRet);
-bool ParseMoney(const char* pszIn, int64_t& nRet);
-std::string SanitizeString(const std::string& str);
-std::vector<unsigned char> ParseHex(const char* psz);
-std::vector<unsigned char> ParseHex(const std::string& str);
-signed char HexDigit(char c);
-bool IsHex(const std::string& str);
-std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = NULL);
-std::string DecodeBase64(const std::string& str);
-std::string EncodeBase64(const unsigned char* pch, size_t len);
-std::string EncodeBase64(const std::string& str);
-std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid = NULL);
-std::string DecodeBase32(const std::string& str);
-std::string EncodeBase32(const unsigned char* pch, size_t len);
-std::string EncodeBase32(const std::string& str);
void ParseParameters(int argc, const char*const argv[]);
void FileCommit(FILE *fileout);
bool TruncateFile(FILE *file, unsigned int length);
@@ -183,111 +103,8 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
boost::filesystem::path GetTempPath();
void ShrinkDebugFile();
-int64_t GetTime();
-void SetMockTime(int64_t nMockTimeIn);
-std::string FormatFullVersion();
-std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments);
void runCommand(std::string strCommand);
-inline std::string i64tostr(int64_t n)
-{
- return strprintf("%d", n);
-}
-
-inline std::string itostr(int n)
-{
- return strprintf("%d", n);
-}
-
-inline int64_t atoi64(const char* psz)
-{
-#ifdef _MSC_VER
- return _atoi64(psz);
-#else
- return strtoll(psz, NULL, 10);
-#endif
-}
-
-inline int64_t atoi64(const std::string& str)
-{
-#ifdef _MSC_VER
- return _atoi64(str.c_str());
-#else
- return strtoll(str.c_str(), NULL, 10);
-#endif
-}
-
-inline int atoi(const std::string& str)
-{
- return atoi(str.c_str());
-}
-
-/**
- * Convert string to signed 32-bit integer with strict parse error feedback.
- * @returns true if the entire string could be parsed as valid integer,
- * false if not the entire string could be parsed or when overflow or underflow occured.
- */
-bool ParseInt32(const std::string& str, int32_t *out);
-
-inline int roundint(double d)
-{
- return (int)(d > 0 ? d + 0.5 : d - 0.5);
-}
-
-inline int64_t roundint64(double d)
-{
- return (int64_t)(d > 0 ? d + 0.5 : d - 0.5);
-}
-
-inline int64_t abs64(int64_t n)
-{
- return (n >= 0 ? n : -n);
-}
-
-template<typename T>
-std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
-{
- std::string rv;
- static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
- rv.reserve((itend-itbegin)*3);
- for(T it = itbegin; it < itend; ++it)
- {
- unsigned char val = (unsigned char)(*it);
- if(fSpaces && it != itbegin)
- rv.push_back(' ');
- rv.push_back(hexmap[val>>4]);
- rv.push_back(hexmap[val&15]);
- }
-
- return rv;
-}
-
-template<typename T>
-inline std::string HexStr(const T& vch, bool fSpaces=false)
-{
- return HexStr(vch.begin(), vch.end(), fSpaces);
-}
-
-/** Format a paragraph of text to a fixed width, adding spaces for
- * indentation to any added line.
- */
-std::string FormatParagraph(const std::string in, size_t width=79, size_t indent=0);
-
-inline int64_t GetTimeMillis()
-{
- return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) -
- boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds();
-}
-
-inline int64_t GetTimeMicros()
-{
- return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) -
- boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds();
-}
-
-std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime);
-
inline bool IsSwitchChar(char c)
{
#ifdef WIN32
@@ -342,113 +159,9 @@ bool SoftSetArg(const std::string& strArg, const std::string& strValue);
*/
bool SoftSetBoolArg(const std::string& strArg, bool fValue);
-/**
- * Timing-attack-resistant comparison.
- * Takes time proportional to length
- * of first argument.
- */
-template <typename T>
-bool TimingResistantEqual(const T& a, const T& b)
-{
- if (b.size() == 0) return a.size() == 0;
- size_t accumulator = a.size() ^ b.size();
- for (size_t i = 0; i < a.size(); i++)
- accumulator |= a[i] ^ b[i%b.size()];
- return accumulator == 0;
-}
-
-/** Median filter over a stream of values.
- * Returns the median of the last N numbers
- */
-template <typename T> class CMedianFilter
-{
-private:
- std::vector<T> vValues;
- std::vector<T> vSorted;
- unsigned int nSize;
-public:
- CMedianFilter(unsigned int size, T initial_value):
- nSize(size)
- {
- vValues.reserve(size);
- vValues.push_back(initial_value);
- vSorted = vValues;
- }
-
- void input(T value)
- {
- if(vValues.size() == nSize)
- {
- vValues.erase(vValues.begin());
- }
- vValues.push_back(value);
-
- vSorted.resize(vValues.size());
- std::copy(vValues.begin(), vValues.end(), vSorted.begin());
- std::sort(vSorted.begin(), vSorted.end());
- }
-
- T median() const
- {
- int size = vSorted.size();
- assert(size>0);
- if(size & 1) // Odd number of elements
- {
- return vSorted[size/2];
- }
- else // Even number of elements
- {
- return (vSorted[size/2-1] + vSorted[size/2]) / 2;
- }
- }
-
- int size() const
- {
- return vValues.size();
- }
-
- std::vector<T> sorted () const
- {
- return vSorted;
- }
-};
-
-#ifdef WIN32
-inline void SetThreadPriority(int nPriority)
-{
- SetThreadPriority(GetCurrentThread(), nPriority);
-}
-#else
-
-// PRIO_MAX is not defined on Solaris
-#ifndef PRIO_MAX
-#define PRIO_MAX 20
-#endif
-#define THREAD_PRIORITY_LOWEST PRIO_MAX
-#define THREAD_PRIORITY_BELOW_NORMAL 2
-#define THREAD_PRIORITY_NORMAL 0
-#define THREAD_PRIORITY_ABOVE_NORMAL (-2)
-
-inline void SetThreadPriority(int nPriority)
-{
- // It's unclear if it's even possible to change thread priorities on Linux,
- // but we really and truly need it for the generation threads.
-#ifdef PRIO_THREAD
- setpriority(PRIO_THREAD, 0, nPriority);
-#else
- setpriority(PRIO_PROCESS, 0, nPriority);
-#endif
-}
-#endif
-
+void SetThreadPriority(int nPriority);
void RenameThread(const char* name);
-inline uint32_t ByteReverse(uint32_t value)
-{
- value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8);
- return (value<<16) | (value>>16);
-}
-
// Standard wrapper for do-something-forever thread functions.
// "Forever" really means until the thread is interrupted.
// Use it like:
diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp
new file mode 100644
index 0000000000..1bd48d8d4c
--- /dev/null
+++ b/src/utilmoneystr.cpp
@@ -0,0 +1,75 @@
+#include "utilmoneystr.h"
+
+#include "core.h"
+#include "tinyformat.h"
+
+using namespace std;
+
+string FormatMoney(int64_t n, bool fPlus)
+{
+ // Note: not using straight sprintf here because we do NOT want
+ // localized number formatting.
+ int64_t n_abs = (n > 0 ? n : -n);
+ int64_t quotient = n_abs/COIN;
+ int64_t remainder = n_abs%COIN;
+ string str = strprintf("%d.%08d", quotient, remainder);
+
+ // Right-trim excess zeros before the decimal point:
+ int nTrim = 0;
+ for (int i = str.size()-1; (str[i] == '0' && isdigit(str[i-2])); --i)
+ ++nTrim;
+ if (nTrim)
+ str.erase(str.size()-nTrim, nTrim);
+
+ if (n < 0)
+ str.insert((unsigned int)0, 1, '-');
+ else if (fPlus && n > 0)
+ str.insert((unsigned int)0, 1, '+');
+ return str;
+}
+
+
+bool ParseMoney(const string& str, int64_t& nRet)
+{
+ return ParseMoney(str.c_str(), nRet);
+}
+
+bool ParseMoney(const char* pszIn, int64_t& nRet)
+{
+ string strWhole;
+ int64_t nUnits = 0;
+ const char* p = pszIn;
+ while (isspace(*p))
+ p++;
+ for (; *p; p++)
+ {
+ if (*p == '.')
+ {
+ p++;
+ int64_t nMult = CENT*10;
+ while (isdigit(*p) && (nMult > 0))
+ {
+ nUnits += nMult * (*p++ - '0');
+ nMult /= 10;
+ }
+ break;
+ }
+ if (isspace(*p))
+ break;
+ if (!isdigit(*p))
+ return false;
+ strWhole.insert(strWhole.end(), *p);
+ }
+ for (; *p; p++)
+ if (!isspace(*p))
+ return false;
+ if (strWhole.size() > 10) // guard against 63 bit overflow
+ return false;
+ if (nUnits < 0 || nUnits > COIN)
+ return false;
+ int64_t nWhole = atoi64(strWhole);
+ int64_t nValue = nWhole*COIN + nUnits;
+
+ nRet = nValue;
+ return true;
+}
diff --git a/src/utilmoneystr.h b/src/utilmoneystr.h
new file mode 100644
index 0000000000..f0c61aa138
--- /dev/null
+++ b/src/utilmoneystr.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+/**
+ * Money parsing/formatting utilities.
+ */
+#ifndef BITCOIN_UTILMONEYSTR_H
+#define BITCOIN_UTILMONEYSTR_H
+
+#include <stdint.h>
+#include <string>
+
+std::string FormatMoney(int64_t n, bool fPlus=false);
+bool ParseMoney(const std::string& str, int64_t& nRet);
+bool ParseMoney(const char* pszIn, int64_t& nRet);
+
+#endif // BITCOIN_UTILMONEYSTR_H
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp
new file mode 100644
index 0000000000..ef13555104
--- /dev/null
+++ b/src/utilstrencodings.cpp
@@ -0,0 +1,496 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "utilstrencodings.h"
+
+#include "tinyformat.h"
+
+#include <boost/foreach.hpp>
+#include <errno.h>
+#include <limits>
+
+using namespace std;
+
+// safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything
+// even possibly remotely dangerous like & or >
+static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@");
+string SanitizeString(const string& str)
+{
+ string strResult;
+ for (std::string::size_type i = 0; i < str.size(); i++)
+ {
+ if (safeChars.find(str[i]) != std::string::npos)
+ strResult.push_back(str[i]);
+ }
+ return strResult;
+}
+
+const signed char p_util_hexdigit[256] =
+{ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
+ -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
+
+signed char HexDigit(char c)
+{
+ return p_util_hexdigit[(unsigned char)c];
+}
+
+bool IsHex(const string& str)
+{
+ BOOST_FOREACH(char c, str)
+ {
+ if (HexDigit(c) < 0)
+ return false;
+ }
+ return (str.size() > 0) && (str.size()%2 == 0);
+}
+
+vector<unsigned char> ParseHex(const char* psz)
+{
+ // convert hex dump to vector
+ vector<unsigned char> vch;
+ while (true)
+ {
+ while (isspace(*psz))
+ psz++;
+ signed char c = HexDigit(*psz++);
+ if (c == (signed char)-1)
+ break;
+ unsigned char n = (c << 4);
+ c = HexDigit(*psz++);
+ if (c == (signed char)-1)
+ break;
+ n |= c;
+ vch.push_back(n);
+ }
+ return vch;
+}
+
+vector<unsigned char> ParseHex(const string& str)
+{
+ return ParseHex(str.c_str());
+}
+
+string EncodeBase64(const unsigned char* pch, size_t len)
+{
+ static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ string strRet="";
+ strRet.reserve((len+2)/3*4);
+
+ int mode=0, left=0;
+ const unsigned char *pchEnd = pch+len;
+
+ while (pch<pchEnd)
+ {
+ int enc = *(pch++);
+ switch (mode)
+ {
+ case 0: // we have no bits
+ strRet += pbase64[enc >> 2];
+ left = (enc & 3) << 4;
+ mode = 1;
+ break;
+
+ case 1: // we have two bits
+ strRet += pbase64[left | (enc >> 4)];
+ left = (enc & 15) << 2;
+ mode = 2;
+ break;
+
+ case 2: // we have four bits
+ strRet += pbase64[left | (enc >> 6)];
+ strRet += pbase64[enc & 63];
+ mode = 0;
+ break;
+ }
+ }
+
+ if (mode)
+ {
+ strRet += pbase64[left];
+ strRet += '=';
+ if (mode == 1)
+ strRet += '=';
+ }
+
+ return strRet;
+}
+
+string EncodeBase64(const string& str)
+{
+ return EncodeBase64((const unsigned char*)str.c_str(), str.size());
+}
+
+vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid)
+{
+ static const int decode64_table[256] =
+ {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1,
+ -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+ };
+
+ if (pfInvalid)
+ *pfInvalid = false;
+
+ vector<unsigned char> vchRet;
+ vchRet.reserve(strlen(p)*3/4);
+
+ int mode = 0;
+ int left = 0;
+
+ while (1)
+ {
+ int dec = decode64_table[(unsigned char)*p];
+ if (dec == -1) break;
+ p++;
+ switch (mode)
+ {
+ case 0: // we have no bits and get 6
+ left = dec;
+ mode = 1;
+ break;
+
+ case 1: // we have 6 bits and keep 4
+ vchRet.push_back((left<<2) | (dec>>4));
+ left = dec & 15;
+ mode = 2;
+ break;
+
+ case 2: // we have 4 bits and get 6, we keep 2
+ vchRet.push_back((left<<4) | (dec>>2));
+ left = dec & 3;
+ mode = 3;
+ break;
+
+ case 3: // we have 2 bits and get 6
+ vchRet.push_back((left<<6) | dec);
+ mode = 0;
+ break;
+ }
+ }
+
+ if (pfInvalid)
+ switch (mode)
+ {
+ case 0: // 4n base64 characters processed: ok
+ break;
+
+ case 1: // 4n+1 base64 character processed: impossible
+ *pfInvalid = true;
+ break;
+
+ case 2: // 4n+2 base64 characters processed: require '=='
+ if (left || p[0] != '=' || p[1] != '=' || decode64_table[(unsigned char)p[2]] != -1)
+ *pfInvalid = true;
+ break;
+
+ case 3: // 4n+3 base64 characters processed: require '='
+ if (left || p[0] != '=' || decode64_table[(unsigned char)p[1]] != -1)
+ *pfInvalid = true;
+ break;
+ }
+
+ return vchRet;
+}
+
+string DecodeBase64(const string& str)
+{
+ vector<unsigned char> vchRet = DecodeBase64(str.c_str());
+ return string((const char*)&vchRet[0], vchRet.size());
+}
+
+string EncodeBase32(const unsigned char* pch, size_t len)
+{
+ static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567";
+
+ string strRet="";
+ strRet.reserve((len+4)/5*8);
+
+ int mode=0, left=0;
+ const unsigned char *pchEnd = pch+len;
+
+ while (pch<pchEnd)
+ {
+ int enc = *(pch++);
+ switch (mode)
+ {
+ case 0: // we have no bits
+ strRet += pbase32[enc >> 3];
+ left = (enc & 7) << 2;
+ mode = 1;
+ break;
+
+ case 1: // we have three bits
+ strRet += pbase32[left | (enc >> 6)];
+ strRet += pbase32[(enc >> 1) & 31];
+ left = (enc & 1) << 4;
+ mode = 2;
+ break;
+
+ case 2: // we have one bit
+ strRet += pbase32[left | (enc >> 4)];
+ left = (enc & 15) << 1;
+ mode = 3;
+ break;
+
+ case 3: // we have four bits
+ strRet += pbase32[left | (enc >> 7)];
+ strRet += pbase32[(enc >> 2) & 31];
+ left = (enc & 3) << 3;
+ mode = 4;
+ break;
+
+ case 4: // we have two bits
+ strRet += pbase32[left | (enc >> 5)];
+ strRet += pbase32[enc & 31];
+ mode = 0;
+ }
+ }
+
+ static const int nPadding[5] = {0, 6, 4, 3, 1};
+ if (mode)
+ {
+ strRet += pbase32[left];
+ for (int n=0; n<nPadding[mode]; n++)
+ strRet += '=';
+ }
+
+ return strRet;
+}
+
+string EncodeBase32(const string& str)
+{
+ return EncodeBase32((const unsigned char*)str.c_str(), str.size());
+}
+
+vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid)
+{
+ static const int decode32_table[256] =
+ {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+ };
+
+ if (pfInvalid)
+ *pfInvalid = false;
+
+ vector<unsigned char> vchRet;
+ vchRet.reserve((strlen(p))*5/8);
+
+ int mode = 0;
+ int left = 0;
+
+ while (1)
+ {
+ int dec = decode32_table[(unsigned char)*p];
+ if (dec == -1) break;
+ p++;
+ switch (mode)
+ {
+ case 0: // we have no bits and get 5
+ left = dec;
+ mode = 1;
+ break;
+
+ case 1: // we have 5 bits and keep 2
+ vchRet.push_back((left<<3) | (dec>>2));
+ left = dec & 3;
+ mode = 2;
+ break;
+
+ case 2: // we have 2 bits and keep 7
+ left = left << 5 | dec;
+ mode = 3;
+ break;
+
+ case 3: // we have 7 bits and keep 4
+ vchRet.push_back((left<<1) | (dec>>4));
+ left = dec & 15;
+ mode = 4;
+ break;
+
+ case 4: // we have 4 bits, and keep 1
+ vchRet.push_back((left<<4) | (dec>>1));
+ left = dec & 1;
+ mode = 5;
+ break;
+
+ case 5: // we have 1 bit, and keep 6
+ left = left << 5 | dec;
+ mode = 6;
+ break;
+
+ case 6: // we have 6 bits, and keep 3
+ vchRet.push_back((left<<2) | (dec>>3));
+ left = dec & 7;
+ mode = 7;
+ break;
+
+ case 7: // we have 3 bits, and keep 0
+ vchRet.push_back((left<<5) | dec);
+ mode = 0;
+ break;
+ }
+ }
+
+ if (pfInvalid)
+ switch (mode)
+ {
+ case 0: // 8n base32 characters processed: ok
+ break;
+
+ case 1: // 8n+1 base32 characters processed: impossible
+ case 3: // +3
+ case 6: // +6
+ *pfInvalid = true;
+ break;
+
+ case 2: // 8n+2 base32 characters processed: require '======'
+ if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || p[4] != '=' || p[5] != '=' || decode32_table[(unsigned char)p[6]] != -1)
+ *pfInvalid = true;
+ break;
+
+ case 4: // 8n+4 base32 characters processed: require '===='
+ if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || decode32_table[(unsigned char)p[4]] != -1)
+ *pfInvalid = true;
+ break;
+
+ case 5: // 8n+5 base32 characters processed: require '==='
+ if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || decode32_table[(unsigned char)p[3]] != -1)
+ *pfInvalid = true;
+ break;
+
+ case 7: // 8n+7 base32 characters processed: require '='
+ if (left || p[0] != '=' || decode32_table[(unsigned char)p[1]] != -1)
+ *pfInvalid = true;
+ break;
+ }
+
+ return vchRet;
+}
+
+string DecodeBase32(const string& str)
+{
+ vector<unsigned char> vchRet = DecodeBase32(str.c_str());
+ return string((const char*)&vchRet[0], vchRet.size());
+}
+
+bool ParseInt32(const std::string& str, int32_t *out)
+{
+ char *endp = NULL;
+ errno = 0; // strtol will not set errno if valid
+ long int n = strtol(str.c_str(), &endp, 10);
+ if(out) *out = (int)n;
+ // Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
+ // we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
+ // platforms the size of these types may be different.
+ return endp && *endp == 0 && !errno &&
+ n >= std::numeric_limits<int32_t>::min() &&
+ n <= std::numeric_limits<int32_t>::max();
+}
+
+std::string FormatParagraph(const std::string in, size_t width, size_t indent)
+{
+ std::stringstream out;
+ size_t col = 0;
+ size_t ptr = 0;
+ while(ptr < in.size())
+ {
+ // Find beginning of next word
+ ptr = in.find_first_not_of(' ', ptr);
+ if (ptr == std::string::npos)
+ break;
+ // Find end of next word
+ size_t endword = in.find_first_of(' ', ptr);
+ if (endword == std::string::npos)
+ endword = in.size();
+ // Add newline and indentation if this wraps over the allowed width
+ if (col > 0)
+ {
+ if ((col + endword - ptr) > width)
+ {
+ out << '\n';
+ for(size_t i=0; i<indent; ++i)
+ out << ' ';
+ col = 0;
+ } else
+ out << ' ';
+ }
+ // Append word
+ out << in.substr(ptr, endword - ptr);
+ col += endword - ptr;
+ ptr = endword;
+ }
+ return out.str();
+}
+
+std::string i64tostr(int64_t n)
+{
+ return strprintf("%d", n);
+}
+
+std::string itostr(int n)
+{
+ return strprintf("%d", n);
+}
+
+int64_t atoi64(const char* psz)
+{
+#ifdef _MSC_VER
+ return _atoi64(psz);
+#else
+ return strtoll(psz, NULL, 10);
+#endif
+}
+
+int64_t atoi64(const std::string& str)
+{
+#ifdef _MSC_VER
+ return _atoi64(str.c_str());
+#else
+ return strtoll(str.c_str(), NULL, 10);
+#endif
+}
+
+int atoi(const std::string& str)
+{
+ return atoi(str.c_str());
+}
diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h
new file mode 100644
index 0000000000..0b8c1a1781
--- /dev/null
+++ b/src/utilstrencodings.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+/**
+ * Utilities for converting data from/to strings.
+ */
+#ifndef BITCOIN_UTILSTRENCODINGS_H
+#define BITCOIN_UTILSTRENCODINGS_H
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#define BEGIN(a) ((char*)&(a))
+#define END(a) ((char*)&((&(a))[1]))
+#define UBEGIN(a) ((unsigned char*)&(a))
+#define UEND(a) ((unsigned char*)&((&(a))[1]))
+#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0]))
+
+// This is needed because the foreach macro can't get over the comma in pair<t1, t2>
+#define PAIRTYPE(t1, t2) std::pair<t1, t2>
+
+std::string SanitizeString(const std::string& str);
+std::vector<unsigned char> ParseHex(const char* psz);
+std::vector<unsigned char> ParseHex(const std::string& str);
+signed char HexDigit(char c);
+bool IsHex(const std::string& str);
+std::vector<unsigned char> DecodeBase64(const char* p, bool* pfInvalid = NULL);
+std::string DecodeBase64(const std::string& str);
+std::string EncodeBase64(const unsigned char* pch, size_t len);
+std::string EncodeBase64(const std::string& str);
+std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid = NULL);
+std::string DecodeBase32(const std::string& str);
+std::string EncodeBase32(const unsigned char* pch, size_t len);
+std::string EncodeBase32(const std::string& str);
+
+std::string i64tostr(int64_t n);
+std::string itostr(int n);
+int64_t atoi64(const char* psz);
+int64_t atoi64(const std::string& str);
+int atoi(const std::string& str);
+
+/**
+ * Convert string to signed 32-bit integer with strict parse error feedback.
+ * @returns true if the entire string could be parsed as valid integer,
+ * false if not the entire string could be parsed or when overflow or underflow occured.
+ */
+bool ParseInt32(const std::string& str, int32_t *out);
+
+template<typename T>
+std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
+{
+ std::string rv;
+ static const char hexmap[16] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+ rv.reserve((itend-itbegin)*3);
+ for(T it = itbegin; it < itend; ++it)
+ {
+ unsigned char val = (unsigned char)(*it);
+ if(fSpaces && it != itbegin)
+ rv.push_back(' ');
+ rv.push_back(hexmap[val>>4]);
+ rv.push_back(hexmap[val&15]);
+ }
+
+ return rv;
+}
+
+template<typename T>
+inline std::string HexStr(const T& vch, bool fSpaces=false)
+{
+ return HexStr(vch.begin(), vch.end(), fSpaces);
+}
+
+/** Format a paragraph of text to a fixed width, adding spaces for
+ * indentation to any added line.
+ */
+std::string FormatParagraph(const std::string in, size_t width=79, size_t indent=0);
+
+/**
+ * Timing-attack-resistant comparison.
+ * Takes time proportional to length
+ * of first argument.
+ */
+template <typename T>
+bool TimingResistantEqual(const T& a, const T& b)
+{
+ if (b.size() == 0) return a.size() == 0;
+ size_t accumulator = a.size() ^ b.size();
+ for (size_t i = 0; i < a.size(); i++)
+ accumulator |= a[i] ^ b[i%b.size()];
+ return accumulator == 0;
+}
+
+#endif // BITCOIN_UTILSTRENCODINGS_H
diff --git a/src/utiltime.cpp b/src/utiltime.cpp
new file mode 100644
index 0000000000..78f0342cba
--- /dev/null
+++ b/src/utiltime.cpp
@@ -0,0 +1,66 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#if defined(HAVE_CONFIG_H)
+#include "config/bitcoin-config.h"
+#endif
+
+#include "utiltime.h"
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/thread.hpp>
+
+using namespace std;
+
+static int64_t nMockTime = 0; // For unit testing
+
+int64_t GetTime()
+{
+ if (nMockTime) return nMockTime;
+
+ return time(NULL);
+}
+
+void SetMockTime(int64_t nMockTimeIn)
+{
+ nMockTime = nMockTimeIn;
+}
+
+int64_t GetTimeMillis()
+{
+ return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) -
+ boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds();
+}
+
+int64_t GetTimeMicros()
+{
+ return (boost::posix_time::ptime(boost::posix_time::microsec_clock::universal_time()) -
+ boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds();
+}
+
+void MilliSleep(int64_t n)
+{
+// Boost's sleep_for was uninterruptable when backed by nanosleep from 1.50
+// until fixed in 1.52. Use the deprecated sleep method for the broken case.
+// See: https://svn.boost.org/trac/boost/ticket/7238
+#if defined(HAVE_WORKING_BOOST_SLEEP_FOR)
+ boost::this_thread::sleep_for(boost::chrono::milliseconds(n));
+#elif defined(HAVE_WORKING_BOOST_SLEEP)
+ boost::this_thread::sleep(boost::posix_time::milliseconds(n));
+#else
+//should never get here
+#error missing boost sleep implementation
+#endif
+}
+
+std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime)
+{
+ // std::locale takes ownership of the pointer
+ std::locale loc(std::locale::classic(), new boost::posix_time::time_facet(pszFormat));
+ std::stringstream ss;
+ ss.imbue(loc);
+ ss << boost::posix_time::from_time_t(nTime);
+ return ss.str();
+}
diff --git a/src/utiltime.h b/src/utiltime.h
new file mode 100644
index 0000000000..500ae4dab9
--- /dev/null
+++ b/src/utiltime.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT/X11 software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_UTILTIME_H
+#define BITCOIN_UTILTIME_H
+
+#include <stdint.h>
+#include <string>
+
+int64_t GetTime();
+int64_t GetTimeMillis();
+int64_t GetTimeMicros();
+void SetMockTime(int64_t nMockTimeIn);
+void MilliSleep(int64_t n);
+
+std::string DateTimeStrFormat(const char* pszFormat, int64_t nTime);
+
+#endif
diff --git a/src/version.cpp b/src/version.cpp
index d86caa3ac2..8311041ed2 100644
--- a/src/version.cpp
+++ b/src/version.cpp
@@ -4,7 +4,10 @@
#include "version.h"
+#include "tinyformat.h"
+
#include <string>
+#include <boost/algorithm/string/join.hpp>
// Name of client reported in the 'version' message. Report the same name
// for both bitcoind and bitcoin-qt, to make it harder for attackers to
@@ -69,3 +72,28 @@ const std::string CLIENT_NAME("Satoshi");
const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);
const std::string CLIENT_DATE(BUILD_DATE);
+
+static std::string FormatVersion(int nVersion)
+{
+ if (nVersion%100 == 0)
+ return strprintf("%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100);
+ else
+ return strprintf("%d.%d.%d.%d", nVersion/1000000, (nVersion/10000)%100, (nVersion/100)%100, nVersion%100);
+}
+
+std::string FormatFullVersion()
+{
+ return CLIENT_BUILD;
+}
+
+// Format the subversion field according to BIP 14 spec (https://en.bitcoin.it/wiki/BIP_0014)
+std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments)
+{
+ std::ostringstream ss;
+ ss << "/";
+ ss << name << ":" << FormatVersion(nClientVersion);
+ if (!comments.empty())
+ ss << "(" << boost::algorithm::join(comments, "; ") << ")";
+ ss << "/";
+ return ss.str();
+}
diff --git a/src/version.h b/src/version.h
index 85c5dbf8d7..3a6c0f3719 100644
--- a/src/version.h
+++ b/src/version.h
@@ -7,6 +7,7 @@
#include "clientversion.h"
#include <string>
+#include <vector>
//
// client versioning
@@ -26,7 +27,7 @@ extern const std::string CLIENT_DATE;
// network protocol versioning
//
-static const int PROTOCOL_VERSION = 70002;
+static const int PROTOCOL_VERSION = 70003;
// initial proto version, to be increased after version/verack negotiation
static const int INIT_PROTO_VERSION = 209;
@@ -48,4 +49,7 @@ static const int BIP0031_VERSION = 60000;
// "mempool" command, enhanced "getdata" behavior starts with this version
static const int MEMPOOL_GD_VERSION = 60002;
+std::string FormatFullVersion();
+std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector<std::string>& comments);
+
#endif
diff --git a/src/wallet.cpp b/src/wallet.cpp
index a293664f6d..786b2f6a92 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -10,8 +10,11 @@
#include "coincontrol.h"
#include "net.h"
#include "timedata.h"
+#include "util.h"
+#include "utilmoneystr.h"
#include <boost/algorithm/string/replace.hpp>
+#include <boost/thread.hpp>
using namespace std;
@@ -37,6 +40,11 @@ struct CompareValueOnly
}
};
+std::string COutput::ToString() const
+{
+ return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->vout[i].nValue).c_str());
+}
+
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
{
LOCK(cs_wallet);
@@ -2169,3 +2177,20 @@ bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, st
}
return false;
}
+
+CKeyPool::CKeyPool()
+{
+ nTime = GetTime();
+}
+
+CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn)
+{
+ nTime = GetTime();
+ vchPubKey = vchPubKeyIn;
+}
+
+CWalletKey::CWalletKey(int64_t nExpires)
+{
+ nTimeCreated = (nExpires ? GetTime() : 0);
+ nTimeExpires = nExpires;
+}
diff --git a/src/wallet.h b/src/wallet.h
index 1f727aec0b..052da24609 100644
--- a/src/wallet.h
+++ b/src/wallet.h
@@ -11,7 +11,6 @@
#include "keystore.h"
#include "main.h"
#include "ui_interface.h"
-#include "util.h"
#include "walletdb.h"
#include <algorithm>
@@ -61,16 +60,8 @@ public:
int64_t nTime;
CPubKey vchPubKey;
- CKeyPool()
- {
- nTime = GetTime();
- }
-
- CKeyPool(const CPubKey& vchPubKeyIn)
- {
- nTime = GetTime();
- vchPubKey = vchPubKeyIn;
- }
+ CKeyPool();
+ CKeyPool(const CPubKey& vchPubKeyIn);
IMPLEMENT_SERIALIZE
(
@@ -823,15 +814,7 @@ public:
tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn;
}
- std::string ToString() const
- {
- return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->vout[i].nValue).c_str());
- }
-
- void print() const
- {
- LogPrintf("%s\n", ToString());
- }
+ std::string ToString() const;
};
@@ -848,11 +831,7 @@ public:
//// todo: add something to note what created it (user, getnewaddress, change)
//// maybe should have a map<string, string> property map
- CWalletKey(int64_t nExpires=0)
- {
- nTimeCreated = (nExpires ? GetTime() : 0);
- nTimeExpires = nExpires;
- }
+ CWalletKey(int64_t nExpires=0);
IMPLEMENT_SERIALIZE
(
@@ -861,7 +840,7 @@ public:
READWRITE(vchPrivKey);
READWRITE(nTimeCreated);
READWRITE(nTimeExpires);
- READWRITE(strComment);
+ READWRITE(LIMITED_STRING(strComment, 65536));
)
};
@@ -936,7 +915,7 @@ public:
// Note: strAccount is serialized as part of the key, not here.
READWRITE(nCreditDebit);
READWRITE(nTime);
- READWRITE(strOtherAccount);
+ READWRITE(LIMITED_STRING(strOtherAccount, 65536));
if (!fRead)
{
@@ -952,7 +931,7 @@ public:
}
}
- READWRITE(strComment);
+ READWRITE(LIMITED_STRING(strComment, 65536));
size_t nSepPos = strComment.find("\0", 0, 1);
if (fRead)
diff --git a/src/walletdb.cpp b/src/walletdb.cpp
index a95baf83d0..2fa6071658 100644
--- a/src/walletdb.cpp
+++ b/src/walletdb.cpp
@@ -9,10 +9,13 @@
#include "protocol.h"
#include "serialize.h"
#include "sync.h"
+#include "utiltime.h"
+#include "util.h"
#include "wallet.h"
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
+#include <boost/thread.hpp>
using namespace std;
using namespace boost;