aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am13
-rw-r--r--src/addrman.cpp8
-rw-r--r--src/addrman.h2
-rw-r--r--src/alert.cpp4
-rw-r--r--src/alert.h2
-rw-r--r--src/bitcoin-cli.cpp32
-rw-r--r--src/bitcoin-tx.cpp4
-rw-r--r--src/chain.cpp7
-rw-r--r--src/chainparams.cpp1
-rw-r--r--src/checkpoints.cpp9
-rw-r--r--src/checkpoints.h3
-rw-r--r--src/coincontrol.h5
-rw-r--r--src/compat/endian.h2
-rw-r--r--src/consensus/validation.h2
-rw-r--r--src/core_io.h2
-rw-r--r--src/core_read.cpp2
-rw-r--r--src/init.cpp193
-rw-r--r--src/json/LICENSE.txt24
-rw-r--r--src/json/json_spirit.h18
-rw-r--r--src/json/json_spirit_error_position.h54
-rw-r--r--src/json/json_spirit_reader.cpp137
-rw-r--r--src/json/json_spirit_reader.h62
-rw-r--r--src/json/json_spirit_reader_template.h612
-rw-r--r--src/json/json_spirit_stream_reader.h70
-rw-r--r--src/json/json_spirit_utils.h61
-rw-r--r--src/json/json_spirit_value.cpp8
-rw-r--r--src/json/json_spirit_value.h534
-rw-r--r--src/json/json_spirit_writer.cpp95
-rw-r--r--src/json/json_spirit_writer.h50
-rw-r--r--src/json/json_spirit_writer_template.h249
-rw-r--r--src/main.cpp115
-rw-r--r--src/main.h14
-rw-r--r--src/net.cpp89
-rw-r--r--src/net.h15
-rw-r--r--src/netbase.cpp5
-rw-r--r--src/netbase.h1
-rw-r--r--src/qt/forms/rpcconsole.ui122
-rw-r--r--src/qt/guiutil.cpp13
-rw-r--r--src/qt/guiutil.h10
-rw-r--r--src/qt/peertablemodel.cpp5
-rw-r--r--src/qt/rpcconsole.cpp98
-rw-r--r--src/qt/rpcconsole.h8
-rw-r--r--src/rest.cpp34
-rw-r--r--src/rpcblockchain.cpp83
-rw-r--r--src/rpcclient.cpp36
-rw-r--r--src/rpcclient.h10
-rw-r--r--src/rpcmining.cpp75
-rw-r--r--src/rpcmisc.cpp64
-rw-r--r--src/rpcnet.cpp204
-rw-r--r--src/rpcprotocol.cpp29
-rw-r--r--src/rpcprotocol.h14
-rw-r--r--src/rpcrawtransaction.cpp122
-rw-r--r--src/rpcserver.cpp158
-rw-r--r--src/rpcserver.h236
-rw-r--r--src/scheduler.cpp4
-rw-r--r--src/script/sign.cpp36
-rw-r--r--src/script/sign.h8
-rw-r--r--src/test/Checkpoints_tests.cpp16
-rw-r--r--src/test/alert_tests.cpp10
-rw-r--r--src/test/base58_tests.cpp58
-rw-r--r--src/test/miner_tests.cpp1
-rw-r--r--src/test/rpc_tests.cpp149
-rw-r--r--src/test/rpc_wallet_tests.cpp21
-rw-r--r--src/test/script_tests.cpp56
-rw-r--r--src/test/sighash_tests.cpp17
-rw-r--r--src/test/transaction_tests.cpp53
-rw-r--r--src/test/univalue_tests.cpp72
-rw-r--r--src/test/util_tests.cpp109
-rw-r--r--src/txdb.cpp5
-rw-r--r--src/univalue/gen.cpp1
-rw-r--r--src/univalue/univalue.cpp107
-rw-r--r--src/univalue/univalue.h102
-rw-r--r--src/univalue/univalue_escapes.h2
-rw-r--r--src/univalue/univalue_read.cpp15
-rw-r--r--src/univalue/univalue_write.cpp9
-rw-r--r--src/util.cpp2
-rw-r--r--src/util.h2
-rw-r--r--src/utilmoneystr.cpp4
-rw-r--r--src/utilmoneystr.h2
-rw-r--r--src/utilstrencodings.cpp45
-rw-r--r--src/utilstrencodings.h18
-rw-r--r--src/validationinterface.cpp3
-rw-r--r--src/validationinterface.h3
-rw-r--r--src/wallet/db.cpp12
-rw-r--r--src/wallet/db.h4
-rw-r--r--src/wallet/rpcdump.cpp44
-rw-r--r--src/wallet/rpcwallet.cpp365
-rw-r--r--src/wallet/wallet.cpp139
-rw-r--r--src/wallet/wallet.h10
89 files changed, 2196 insertions, 3133 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 1c2f770418..59618c4940 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -154,17 +154,6 @@ BITCOIN_CORE_H = \
wallet/wallet_ismine.h \
wallet/walletdb.h
-JSON_H = \
- json/json_spirit.h \
- json/json_spirit_error_position.h \
- json/json_spirit_reader.h \
- json/json_spirit_reader_template.h \
- json/json_spirit_stream_reader.h \
- json/json_spirit_utils.h \
- json/json_spirit_value.h \
- json/json_spirit_writer.h \
- json/json_spirit_writer_template.h
-
obj/build.h: FORCE
@$(MKDIR_P) $(builddir)/obj
@$(top_srcdir)/share/genbuild.sh $(abs_top_builddir)/src/obj/build.h \
@@ -200,7 +189,6 @@ libbitcoin_server_a_SOURCES = \
txdb.cpp \
txmempool.cpp \
validationinterface.cpp \
- $(JSON_H) \
$(BITCOIN_CORE_H)
# wallet: shared between bitcoind and bitcoin-qt, but only linked
@@ -342,6 +330,7 @@ endif
bitcoin_cli_LDADD = \
$(LIBBITCOIN_CLI) \
+ $(LIBBITCOIN_UNIVALUE) \
$(LIBBITCOIN_UTIL) \
$(LIBSECP256K1)
diff --git a/src/addrman.cpp b/src/addrman.cpp
index c41ee3f9fc..b605f4351d 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -8,8 +8,6 @@
#include "serialize.h"
#include "streams.h"
-using namespace std;
-
int CAddrInfo::GetTriedBucket(const uint256& nKey) const
{
uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetHash().GetCheapHash();
@@ -68,7 +66,7 @@ double CAddrInfo::GetChance(int64_t nNow) const
fChance *= 0.01;
// deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.
- fChance *= pow(0.66, min(nAttempts, 8));
+ fChance *= pow(0.66, std::min(nAttempts, 8));
return fChance;
}
@@ -258,7 +256,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty))
- pinfo->nTime = max((int64_t)0, addr.nTime - nTimePenalty);
+ pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty);
// add services
pinfo->nServices |= addr.nServices;
@@ -283,7 +281,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
return false;
} else {
pinfo = Create(addr, source, &nId);
- pinfo->nTime = max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty);
+ pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty);
nNew++;
fNew = true;
}
diff --git a/src/addrman.h b/src/addrman.h
index 373b0f39f3..2623d89809 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -458,7 +458,7 @@ public:
}
//! Return the number of (unique) addresses in all tables.
- int size()
+ size_t size() const
{
return vRandom.size();
}
diff --git a/src/alert.cpp b/src/alert.cpp
index aa7ac748da..ad81e74226 100644
--- a/src/alert.cpp
+++ b/src/alert.cpp
@@ -50,7 +50,7 @@ std::string CUnsignedAlert::ToString() const
BOOST_FOREACH(int n, setCancel)
strSetCancel += strprintf("%d ", n);
std::string strSetSubVer;
- BOOST_FOREACH(std::string str, setSubVer)
+ BOOST_FOREACH(const std::string& str, setSubVer)
strSetSubVer += "\"" + str + "\" ";
return strprintf(
"CAlert(\n"
@@ -110,7 +110,7 @@ bool CAlert::Cancels(const CAlert& alert) const
return (alert.nID <= nCancel || setCancel.count(alert.nID));
}
-bool CAlert::AppliesTo(int nVersion, std::string strSubVerIn) const
+bool CAlert::AppliesTo(int nVersion, const std::string& strSubVerIn) const
{
// TODO: rework for client-version-embedded-in-strSubVer ?
return (IsInEffect() &&
diff --git a/src/alert.h b/src/alert.h
index 746967c4af..4f9fff9181 100644
--- a/src/alert.h
+++ b/src/alert.h
@@ -97,7 +97,7 @@ public:
uint256 GetHash() const;
bool IsInEffect() const;
bool Cancels(const CAlert& alert) const;
- bool AppliesTo(int nVersion, std::string strSubVerIn) const;
+ bool AppliesTo(int nVersion, const std::string& strSubVerIn) const;
bool AppliesToMe() const;
bool RelayTo(CNode* pnode) const;
bool CheckSignature(const std::vector<unsigned char>& alertKey) const;
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 1269d7a119..d451720141 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -12,8 +12,9 @@
#include <boost/filesystem/operations.hpp>
+#include "univalue/univalue.h"
+
using namespace std;
-using namespace json_spirit;
std::string HelpMessageCli()
{
@@ -94,7 +95,7 @@ static bool AppInitRPC(int argc, char* argv[])
return true;
}
-Object CallRPC(const string& strMethod, const Array& params)
+UniValue CallRPC(const string& strMethod, const UniValue& params)
{
if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
throw runtime_error(strprintf(
@@ -142,10 +143,10 @@ Object CallRPC(const string& strMethod, const Array& params)
throw runtime_error("no response from server");
// Parse reply
- Value valReply;
- if (!read_string(strReply, valReply))
+ UniValue valReply(UniValue::VSTR);
+ if (!valReply.read(strReply))
throw runtime_error("couldn't parse reply from server");
- const Object& reply = valReply.get_obj();
+ const UniValue& reply = valReply.get_obj();
if (reply.empty())
throw runtime_error("expected reply to have result, error and id properties");
@@ -170,35 +171,34 @@ int CommandLineRPC(int argc, char *argv[])
// Parameters default to strings
std::vector<std::string> strParams(&argv[2], &argv[argc]);
- Array params = RPCConvertValues(strMethod, strParams);
+ UniValue params = RPCConvertValues(strMethod, strParams);
// Execute and handle connection failures with -rpcwait
const bool fWait = GetBoolArg("-rpcwait", false);
do {
try {
- const Object reply = CallRPC(strMethod, params);
+ const UniValue reply = CallRPC(strMethod, params);
// Parse reply
- const Value& result = find_value(reply, "result");
- const Value& error = find_value(reply, "error");
+ const UniValue& result = find_value(reply, "result");
+ const UniValue& error = find_value(reply, "error");
- if (error.type() != null_type) {
+ if (!error.isNull()) {
// Error
- const int code = find_value(error.get_obj(), "code").get_int();
+ int code = error["code"].get_int();
if (fWait && code == RPC_IN_WARMUP)
throw CConnectionFailed("server in warmup");
- strPrint = "error: " + write_string(error, false);
+ strPrint = "error: " + error.write();
nRet = abs(code);
} else {
// Result
- if (result.type() == null_type)
+ if (result.isNull())
strPrint = "";
- else if (result.type() == str_type)
+ else if (result.isStr())
strPrint = result.get_str();
else
- strPrint = write_string(result, true);
+ strPrint = result.write(2);
}
-
// Connection succeeded, no need to retry.
break;
}
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index c82d4f93a8..45990f6bd8 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -346,7 +346,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
UniValue keysObj = registers["privatekeys"];
fGivenKeys = true;
- for (unsigned int kidx = 0; kidx < keysObj.count(); kidx++) {
+ for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {
if (!keysObj[kidx].isStr())
throw runtime_error("privatekey not a string");
CBitcoinSecret vchSecret;
@@ -363,7 +363,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
throw runtime_error("prevtxs register variable must be set.");
UniValue prevtxsObj = registers["prevtxs"];
{
- for (unsigned int previdx = 0; previdx < prevtxsObj.count(); previdx++) {
+ for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++) {
UniValue prevOut = prevtxsObj[previdx];
if (!prevOut.isObject())
throw runtime_error("expected prevtxs internal object");
diff --git a/src/chain.cpp b/src/chain.cpp
index 719256106e..5b8ce076c4 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -82,9 +82,10 @@ CBlockIndex* CBlockIndex::GetAncestor(int height)
while (heightWalk > height) {
int heightSkip = GetSkipHeight(heightWalk);
int heightSkipPrev = GetSkipHeight(heightWalk - 1);
- if (heightSkip == height ||
- (heightSkip > height && !(heightSkipPrev < heightSkip - 2 &&
- heightSkipPrev >= height))) {
+ if (pindexWalk->pskip != NULL &&
+ (heightSkip == height ||
+ (heightSkip > height && !(heightSkipPrev < heightSkip - 2 &&
+ heightSkipPrev >= height)))) {
// Only follow pskip if pprev->pskip isn't better than pskip->pprev.
pindexWalk = pindexWalk->pskip;
heightWalk = heightSkip;
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 5f400b265c..7785417518 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -66,6 +66,7 @@ public:
*/
const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
CMutableTransaction txNew;
+ txNew.nVersion = 1;
txNew.vin.resize(1);
txNew.vout.resize(1);
txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 2024486139..87f4ad7f2e 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -24,15 +24,6 @@ namespace Checkpoints {
*/
static const double SIGCHECK_VERIFICATION_FACTOR = 5.0;
- bool CheckBlock(const CCheckpointData& data, int nHeight, const uint256& hash)
- {
- const MapCheckpoints& checkpoints = data.mapCheckpoints;
-
- MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
- if (i == checkpoints.end()) return true;
- return hash == i->second;
- }
-
//! Guess how far we are in the verification process at the given block index
double GuessVerificationProgress(const CCheckpointData& data, CBlockIndex *pindex, bool fSigchecks) {
if (pindex==NULL)
diff --git a/src/checkpoints.h b/src/checkpoints.h
index a720f096c0..001e3cc801 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -26,9 +26,6 @@ struct CCheckpointData {
double fTransactionsPerDay;
};
-//! Returns true if block passes checkpoint checks
-bool CheckBlock(const CCheckpointData& data, int nHeight, const uint256& hash);
-
//! Return conservative estimate of total number of blocks, 0 if unknown
int GetTotalBlocksEstimate(const CCheckpointData& data);
diff --git a/src/coincontrol.h b/src/coincontrol.h
index 92fae9847c..3e8de83c39 100644
--- a/src/coincontrol.h
+++ b/src/coincontrol.h
@@ -12,6 +12,8 @@ class CCoinControl
{
public:
CTxDestination destChange;
+ //! If false, allows unselected inputs, but requires all selected inputs be used
+ bool fAllowOtherInputs;
CCoinControl()
{
@@ -21,6 +23,7 @@ public:
void SetNull()
{
destChange = CNoDestination();
+ fAllowOtherInputs = false;
setSelected.clear();
}
@@ -50,7 +53,7 @@ public:
setSelected.clear();
}
- void ListSelected(std::vector<COutPoint>& vOutpoints)
+ void ListSelected(std::vector<COutPoint>& vOutpoints) const
{
vOutpoints.assign(setSelected.begin(), setSelected.end());
}
diff --git a/src/compat/endian.h b/src/compat/endian.h
index 4d041d6554..9fec2a07fa 100644
--- a/src/compat/endian.h
+++ b/src/compat/endian.h
@@ -15,6 +15,8 @@
#if defined(HAVE_ENDIAN_H)
#include <endian.h>
+#elif defined(HAVE_SYS_ENDIAN_H)
+#include <sys/endian.h>
#endif
#if defined(WORDS_BIGENDIAN)
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index c92bec4fae..a97d983a31 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -48,7 +48,7 @@ public:
unsigned char _chRejectCode=0, std::string _strRejectReason="") {
return DoS(0, ret, _chRejectCode, _strRejectReason);
}
- bool Error(std::string strRejectReasonIn="") {
+ bool Error(const std::string& strRejectReasonIn) {
if (mode == MODE_VALID)
strRejectReason = strRejectReasonIn;
mode = MODE_ERROR;
diff --git a/src/core_io.h b/src/core_io.h
index 0989cf7437..115e3199dc 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -15,7 +15,7 @@ class uint256;
class UniValue;
// core_read.cpp
-extern CScript ParseScript(std::string s);
+extern CScript ParseScript(const std::string& s);
extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx);
extern bool DecodeHexBlk(CBlock&, const std::string& strHexBlk);
extern uint256 ParseHashUV(const UniValue& v, const std::string& strName);
diff --git a/src/core_read.cpp b/src/core_read.cpp
index e064955ff0..f762f2c3b7 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -22,7 +22,7 @@
using namespace std;
-CScript ParseScript(std::string s)
+CScript ParseScript(const std::string& s)
{
CScript result;
diff --git a/src/init.cpp b/src/init.cpp
index 35284992ed..bcdd1f2f3d 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -260,10 +260,13 @@ void OnRPCPreCommand(const CRPCCommand& cmd)
std::string HelpMessage(HelpMessageMode mode)
{
+ const bool showDebug = GetBoolArg("-help-debug", false);
// When adding new options to the categories, please keep and ensure alphabetical ordering.
+ // Do not translate _(...) -help-debug options, Many technical terms, and only a very small audience, so is unnecessary stress to translators.
string strUsage = HelpMessageGroup(_("Options:"));
strUsage += HelpMessageOpt("-?", _("This help message"));
+ strUsage += HelpMessageOpt("-alerts", strprintf(_("Receive and display P2P network alerts (default: %u)"), DEFAULT_ALERTS));
strUsage += HelpMessageOpt("-alertnotify=<cmd>", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)"));
strUsage += HelpMessageOpt("-blocknotify=<cmd>", _("Execute command when the best block changes (%s in cmd is replaced by block hash)"));
strUsage += HelpMessageOpt("-checkblocks=<n>", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), 288));
@@ -318,7 +321,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-timeout=<n>", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT));
#ifdef USE_UPNP
#if USE_UPNP
- strUsage += HelpMessageOpt("-upnp", _("Use UPnP to map the listening port (default: 1 when listening)"));
+ strUsage += HelpMessageOpt("-upnp", _("Use UPnP to map the listening port (default: 1 when listening and no -proxy)"));
#else
strUsage += HelpMessageOpt("-upnp", strprintf(_("Use UPnP to map the listening port (default: %u)"), 0));
#endif
@@ -326,14 +329,13 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-whitebind=<addr>", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6"));
strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") +
" " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway"));
-
#ifdef ENABLE_WALLET
strUsage += HelpMessageGroup(_("Wallet options:"));
strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), 100));
- if (GetBoolArg("-help-debug", false))
- strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for transaction creation (default: %s)"),
+ if (showDebug)
+ strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf("Fees (in BTC/Kb) smaller than this are considered zero fee for transaction creation (default: %s)",
FormatMoney(CWallet::minTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in BTC/kB) to add to transactions you send (default: %s)"), FormatMoney(payTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions") + " " + _("on startup"));
@@ -349,20 +351,19 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") +
" " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)"));
-
#endif
strUsage += HelpMessageGroup(_("Debugging/Testing options:"));
- if (GetBoolArg("-help-debug", false))
+ if (showDebug)
{
- strUsage += HelpMessageOpt("-checkpoints", strprintf(_("Only accept block chain matching built-in checkpoints (default: %u)"), 1));
- strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf(_("Flush database activity from memory pool to disk log every <n> megabytes (default: %u)"), 100));
- strUsage += HelpMessageOpt("-disablesafemode", strprintf(_("Disable safemode, override a real safe mode event (default: %u)"), 0));
- strUsage += HelpMessageOpt("-testsafemode", strprintf(_("Force safe mode (default: %u)"), 0));
- strUsage += HelpMessageOpt("-dropmessagestest=<n>", _("Randomly drop 1 of every <n> network messages"));
- strUsage += HelpMessageOpt("-fuzzmessagestest=<n>", _("Randomly fuzz 1 of every <n> network messages"));
- strUsage += HelpMessageOpt("-flushwallet", strprintf(_("Run a thread to flush wallet periodically (default: %u)"), 1));
- strUsage += HelpMessageOpt("-stopafterblockimport", strprintf(_("Stop running after importing blocks from disk (default: %u)"), 0));
+ strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", 1));
+ strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush database activity from memory pool to disk log every <n> megabytes (default: %u)", 100));
+ strUsage += HelpMessageOpt("-disablesafemode", strprintf("Disable safemode, override a real safe mode event (default: %u)", 0));
+ strUsage += HelpMessageOpt("-testsafemode", strprintf("Force safe mode (default: %u)", 0));
+ strUsage += HelpMessageOpt("-dropmessagestest=<n>", "Randomly drop 1 of every <n> network messages");
+ strUsage += HelpMessageOpt("-fuzzmessagestest=<n>", "Randomly fuzz 1 of every <n> network messages");
+ strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", 1));
+ strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", 0));
}
string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, net, proxy, prune"; // Don't translate these and qt below
if (mode == HMM_BITCOIN_QT)
@@ -376,21 +377,20 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-help-debug", _("Show all debugging options (usage: --help -help-debug)"));
strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), 0));
strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), 1));
- if (GetBoolArg("-help-debug", false))
+ if (showDebug)
{
- strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf(_("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)"), 15));
- strUsage += HelpMessageOpt("-relaypriority", strprintf(_("Require high priority for relaying free or low-fee transactions (default: %u)"), 1));
- strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf(_("Limit size of signature cache to <n> entries (default: %u)"), 50000));
+ strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)", 15));
+ strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", 1));
+ strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> entries (default: %u)", 50000));
}
strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s)"), FormatMoney(::minRelayTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-printtoconsole", _("Send trace/debug info to console instead of debug.log file"));
- if (GetBoolArg("-help-debug", false))
+ if (showDebug)
{
- strUsage += HelpMessageOpt("-printpriority", strprintf(_("Log transaction priority and fee per kB when mining blocks (default: %u)"), 0));
- strUsage += HelpMessageOpt("-privdb", strprintf(_("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)"), 1));
- strUsage += HelpMessageOpt("-regtest", _("Enter regression test mode, which uses a special chain in which blocks can be solved instantly.") + " " +
- _("This is intended for regression testing tools and app development.") + " " +
- _("In this mode -genproclimit controls how many blocks are generated immediately."));
+ strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction priority and fee per kB when mining blocks (default: %u)", 0));
+ strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", 1));
+ strUsage += HelpMessageOpt("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. "
+ "This is intended for regression testing tools and app development.");
}
strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)"));
strUsage += HelpMessageOpt("-testnet", _("Use the test network"));
@@ -403,6 +403,8 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-blockminsize=<n>", strprintf(_("Set minimum block size in bytes (default: %u)"), 0));
strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE));
strUsage += HelpMessageOpt("-blockprioritysize=<n>", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE));
+ if (showDebug)
+ strUsage += HelpMessageOpt("-blockversion=<n>", strprintf("Override block version to test forking scenarios (default: %d)", (int)CBlock::CURRENT_VERSION));
strUsage += HelpMessageGroup(_("RPC server options:"));
strUsage += HelpMessageOpt("-server", _("Accept command line and JSON-RPC commands"));
@@ -424,8 +426,8 @@ std::string HelpMessage(HelpMessageMode mode)
if (mode == HMM_BITCOIN_QT)
{
strUsage += HelpMessageGroup(_("UI Options:"));
- if (GetBoolArg("-help-debug", false)) {
- strUsage += HelpMessageOpt("-allowselfsignedrootcertificates", _("Allow self signed root certificates (default: 0)"));
+ if (showDebug) {
+ strUsage += HelpMessageOpt("-allowselfsignedrootcertificates", "Allow self signed root certificates (default: 0)");
}
strUsage += HelpMessageOpt("-choosedatadir", _("Choose data directory on startup (default: 0)"));
strUsage += HelpMessageOpt("-lang=<lang>", _("Set language, for example \"de_DE\" (default: system locale)"));
@@ -473,24 +475,43 @@ struct CImportingNow
// If we're using -prune with -reindex, then delete block files that will be ignored by the
// reindex. Since reindexing works by starting at block file 0 and looping until a blockfile
-// is missing, and since pruning works by deleting the oldest block file first, just check
-// for block file 0, and if it doesn't exist, delete all the block files in the
-// directory (since they won't be read by the reindex but will take up disk space).
-void DeleteAllBlockFiles()
+// is missing, do the same here to delete any later block files after a gap. Also delete all
+// rev files since they'll be rewritten by the reindex anyway. This ensures that vinfoBlockFile
+// is in sync with what's actually on disk by the time we start downloading, so that pruning
+// works correctly.
+void CleanupBlockRevFiles()
{
- if (boost::filesystem::exists(GetBlockPosFilename(CDiskBlockPos(0, 0), "blk")))
- return;
+ using namespace boost::filesystem;
+ map<string, path> mapBlockFiles;
+
+ // Glob all blk?????.dat and rev?????.dat files from the blocks directory.
+ // Remove the rev files immediately and insert the blk file paths into an
+ // ordered map keyed by block file index.
+ LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n");
+ path blocksdir = GetDataDir() / "blocks";
+ for (directory_iterator it(blocksdir); it != directory_iterator(); it++) {
+ if (is_regular_file(*it) &&
+ it->path().filename().string().length() == 12 &&
+ it->path().filename().string().substr(8,4) == ".dat")
+ {
+ if (it->path().filename().string().substr(0,3) == "blk")
+ mapBlockFiles[it->path().filename().string().substr(3,5)] = it->path();
+ else if (it->path().filename().string().substr(0,3) == "rev")
+ remove(it->path());
+ }
+ }
- LogPrintf("Removing all blk?????.dat and rev?????.dat files for -reindex with -prune\n");
- boost::filesystem::path blocksdir = GetDataDir() / "blocks";
- for (boost::filesystem::directory_iterator it(blocksdir); it != boost::filesystem::directory_iterator(); it++) {
- if (is_regular_file(*it)) {
- if ((it->path().filename().string().length() == 12) &&
- (it->path().filename().string().substr(8,4) == ".dat") &&
- ((it->path().filename().string().substr(0,3) == "blk") ||
- (it->path().filename().string().substr(0,3) == "rev")))
- boost::filesystem::remove(it->path());
+ // Remove all block files that aren't part of a contiguous set starting at
+ // zero by walking the ordered map (keys are block file indices) by
+ // keeping a separate counter. Once we hit a gap (or if 0 doesn't exist)
+ // start removing block files.
+ int nContigCounter = 0;
+ BOOST_FOREACH(const PAIRTYPE(string, path)& item, mapBlockFiles) {
+ if (atoi(item.first) == nContigCounter) {
+ nContigCounter++;
+ continue;
}
+ remove(item.second);
}
}
@@ -535,7 +556,7 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
}
// -loadblock=
- BOOST_FOREACH(boost::filesystem::path &path, vImportFiles) {
+ BOOST_FOREACH(const boost::filesystem::path& path, vImportFiles) {
FILE *file = fopen(path.string().c_str(), "rb");
if (file) {
CImportingNow imp;
@@ -714,16 +735,12 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS;
// if using block pruning, then disable txindex
- // also disable the wallet (for now, until SPV support is implemented in wallet)
if (GetArg("-prune", 0)) {
if (GetBoolArg("-txindex", false))
return InitError(_("Prune mode is incompatible with -txindex."));
#ifdef ENABLE_WALLET
- if (!GetBoolArg("-disablewallet", false)) {
- if (SoftSetBoolArg("-disablewallet", true))
- LogPrintf("%s : parameter interaction: -prune -> setting -disablewallet=1\n", __func__);
- else
- return InitError(_("Can't run with a wallet in prune mode."));
+ if (GetBoolArg("-rescan", false)) {
+ return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
}
#endif
}
@@ -849,6 +866,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", true);
nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes);
+ fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS);
+
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
// Initialize elliptic curve code
@@ -929,15 +948,15 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
std::string warningString;
std::string errorString;
-
+
if (!CWallet::Verify(strWalletFile, warningString, errorString))
return false;
-
+
if (!warningString.empty())
InitWarning(warningString);
if (!errorString.empty())
return InitError(warningString);
-
+
} // (!fDisableWallet)
#endif // ENABLE_WALLET
// ********************************************************* Step 6: network initialization
@@ -946,7 +965,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (mapArgs.count("-onlynet")) {
std::set<enum Network> nets;
- BOOST_FOREACH(std::string snet, mapMultiArgs["-onlynet"]) {
+ BOOST_FOREACH(const std::string& snet, mapMultiArgs["-onlynet"]) {
enum Network net = ParseNetwork(snet);
if (net == NET_UNROUTABLE)
return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet));
@@ -968,31 +987,36 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
}
- proxyType addrProxy;
- bool fProxy = false;
- if (mapArgs.count("-proxy")) {
- addrProxy = proxyType(CService(mapArgs["-proxy"], 9050), GetBoolArg("-proxyrandomize", true));
+ bool proxyRandomize = GetBoolArg("-proxyrandomize", true);
+ // -proxy sets a proxy for all outgoing network traffic
+ // -noproxy (or -proxy=0) as well as the empty string can be used to not set a proxy, this is the default
+ std::string proxyArg = GetArg("-proxy", "");
+ if (proxyArg != "" && proxyArg != "0") {
+ proxyType addrProxy = proxyType(CService(proxyArg, 9050), proxyRandomize);
if (!addrProxy.IsValid())
- return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"]));
+ return InitError(strprintf(_("Invalid -proxy address: '%s'"), proxyArg));
SetProxy(NET_IPV4, addrProxy);
SetProxy(NET_IPV6, addrProxy);
+ SetProxy(NET_TOR, addrProxy);
SetNameProxy(addrProxy);
- fProxy = true;
+ SetReachable(NET_TOR); // by default, -proxy sets onion as reachable, unless -noonion later
}
- // -onion can override normal proxy, -noonion disables connecting to .onion entirely
- if (!(mapArgs.count("-onion") && mapArgs["-onion"] == "0") &&
- (fProxy || mapArgs.count("-onion"))) {
- proxyType addrOnion;
- if (!mapArgs.count("-onion"))
- addrOnion = addrProxy;
- else
- addrOnion = proxyType(CService(mapArgs["-onion"], 9050), GetBoolArg("-proxyrandomize", true));
- if (!addrOnion.IsValid())
- return InitError(strprintf(_("Invalid -onion address: '%s'"), mapArgs["-onion"]));
- SetProxy(NET_TOR, addrOnion);
- SetReachable(NET_TOR);
+ // -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses
+ // -noonion (or -onion=0) disables connecting to .onion entirely
+ // An empty string is used to not override the onion proxy (in which case it defaults to -proxy set above, or none)
+ std::string onionArg = GetArg("-onion", "");
+ if (onionArg != "") {
+ if (onionArg == "0") { // Handle -noonion/-onion=0
+ SetReachable(NET_TOR, false); // set onions as unreachable
+ } else {
+ proxyType addrOnion = proxyType(CService(onionArg, 9050), proxyRandomize);
+ if (!addrOnion.IsValid())
+ return InitError(strprintf(_("Invalid -onion address: '%s'"), onionArg));
+ SetProxy(NET_TOR, addrOnion);
+ SetReachable(NET_TOR);
+ }
}
// see Step 2: parameter interactions for more information about these
@@ -1003,13 +1027,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
bool fBound = false;
if (fListen) {
if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) {
- BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) {
+ BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-bind"]) {
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind));
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
}
- BOOST_FOREACH(std::string strBind, mapMultiArgs["-whitebind"]) {
+ BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-whitebind"]) {
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, 0, false))
return InitError(strprintf(_("Cannot resolve -whitebind address: '%s'"), strBind));
@@ -1029,7 +1053,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
if (mapArgs.count("-externalip")) {
- BOOST_FOREACH(string strAddr, mapMultiArgs["-externalip"]) {
+ BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-externalip"]) {
CService addrLocal(strAddr, GetListenPort(), fNameLookup);
if (!addrLocal.IsValid())
return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr));
@@ -1037,7 +1061,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
}
- BOOST_FOREACH(string strDest, mapMultiArgs["-seednode"])
+ BOOST_FOREACH(const std::string& strDest, mapMultiArgs["-seednode"])
AddOneShot(strDest);
// ********************************************************* Step 7: load block chain
@@ -1110,9 +1134,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (fReindex) {
pblocktree->WriteReindexing(true);
- //If we're reindexing in prune mode, wipe away all our block and undo data files
+ //If we're reindexing in prune mode, wipe away unusable block files and all undo data files
if (fPruneMode)
- DeleteAllBlockFiles();
+ CleanupBlockRevFiles();
}
if (!LoadBlockIndex()) {
@@ -1310,6 +1334,19 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
{
+ //We can't rescan beyond non-pruned blocks, stop and throw an error
+ //this might happen if a user uses a old wallet within a pruned node
+ // or if he ran -disablewallet for a longer time, then decided to re-enable
+ if (fPruneMode)
+ {
+ CBlockIndex *block = chainActive.Tip();
+ while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block)
+ block = block->pprev;
+
+ if (pindexRescan != block)
+ return InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"));
+ }
+
uiInterface.InitMessage(_("Rescanning..."));
LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
nStart = GetTimeMillis();
@@ -1362,7 +1399,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
std::vector<boost::filesystem::path> vImportFiles;
if (mapArgs.count("-loadblock"))
{
- BOOST_FOREACH(string strFile, mapMultiArgs["-loadblock"])
+ BOOST_FOREACH(const std::string& strFile, mapMultiArgs["-loadblock"])
vImportFiles.push_back(strFile);
}
threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles));
@@ -1396,7 +1433,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Monitor the chain, and alert if we get blocks much quicker or slower than expected
int64_t nPowTargetSpacing = Params().GetConsensus().nPowTargetSpacing;
CScheduler::Function f = boost::bind(&PartitionCheck, &IsInitialBlockDownload,
- boost::ref(cs_main), boost::cref(chainActive), nPowTargetSpacing);
+ boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing);
scheduler.scheduleEvery(f, nPowTargetSpacing);
#ifdef ENABLE_WALLET
diff --git a/src/json/LICENSE.txt b/src/json/LICENSE.txt
deleted file mode 100644
index 797d5363b3..0000000000
--- a/src/json/LICENSE.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-The MIT License
-
-Copyright (c) 2007 - 2009 John W. Wilkinson
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
diff --git a/src/json/json_spirit.h b/src/json/json_spirit.h
deleted file mode 100644
index ac1879d5b3..0000000000
--- a/src/json/json_spirit.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef JSON_SPIRIT
-#define JSON_SPIRIT
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-#include "json_spirit_value.h"
-#include "json_spirit_reader.h"
-#include "json_spirit_writer.h"
-#include "json_spirit_utils.h"
-
-#endif
diff --git a/src/json/json_spirit_error_position.h b/src/json/json_spirit_error_position.h
deleted file mode 100644
index 17208507df..0000000000
--- a/src/json/json_spirit_error_position.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef JSON_SPIRIT_ERROR_POSITION
-#define JSON_SPIRIT_ERROR_POSITION
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-#include <string>
-
-namespace json_spirit
-{
- // An Error_position exception is thrown by the "read_or_throw" functions below on finding an error.
- // Note the "read_or_throw" functions are around 3 times slower than the standard functions "read"
- // functions that return a bool.
- //
- struct Error_position
- {
- Error_position();
- Error_position( unsigned int line, unsigned int column, const std::string& reason );
- bool operator==( const Error_position& lhs ) const;
- unsigned int line_;
- unsigned int column_;
- std::string reason_;
- };
-
- inline Error_position::Error_position()
- : line_( 0 )
- , column_( 0 )
- {
- }
-
- inline Error_position::Error_position( unsigned int line, unsigned int column, const std::string& reason )
- : line_( line )
- , column_( column )
- , reason_( reason )
- {
- }
-
- inline bool Error_position::operator==( const Error_position& lhs ) const
- {
- if( this == &lhs ) return true;
-
- return ( reason_ == lhs.reason_ ) &&
- ( line_ == lhs.line_ ) &&
- ( column_ == lhs.column_ );
-}
-}
-
-#endif
diff --git a/src/json/json_spirit_reader.cpp b/src/json/json_spirit_reader.cpp
deleted file mode 100644
index aa4f637226..0000000000
--- a/src/json/json_spirit_reader.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#include "json_spirit_reader.h"
-#include "json_spirit_reader_template.h"
-
-using namespace json_spirit;
-
-bool json_spirit::read( const std::string& s, Value& value )
-{
- return read_string( s, value );
-}
-
-void json_spirit::read_or_throw( const std::string& s, Value& value )
-{
- read_string_or_throw( s, value );
-}
-
-bool json_spirit::read( std::istream& is, Value& value )
-{
- return read_stream( is, value );
-}
-
-void json_spirit::read_or_throw( std::istream& is, Value& value )
-{
- read_stream_or_throw( is, value );
-}
-
-bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value )
-{
- return read_range( begin, end, value );
-}
-
-void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value )
-{
- begin = read_range_or_throw( begin, end, value );
-}
-
-#ifndef BOOST_NO_STD_WSTRING
-
-bool json_spirit::read( const std::wstring& s, wValue& value )
-{
- return read_string( s, value );
-}
-
-void json_spirit::read_or_throw( const std::wstring& s, wValue& value )
-{
- read_string_or_throw( s, value );
-}
-
-bool json_spirit::read( std::wistream& is, wValue& value )
-{
- return read_stream( is, value );
-}
-
-void json_spirit::read_or_throw( std::wistream& is, wValue& value )
-{
- read_stream_or_throw( is, value );
-}
-
-bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value )
-{
- return read_range( begin, end, value );
-}
-
-void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value )
-{
- begin = read_range_or_throw( begin, end, value );
-}
-
-#endif
-
-bool json_spirit::read( const std::string& s, mValue& value )
-{
- return read_string( s, value );
-}
-
-void json_spirit::read_or_throw( const std::string& s, mValue& value )
-{
- read_string_or_throw( s, value );
-}
-
-bool json_spirit::read( std::istream& is, mValue& value )
-{
- return read_stream( is, value );
-}
-
-void json_spirit::read_or_throw( std::istream& is, mValue& value )
-{
- read_stream_or_throw( is, value );
-}
-
-bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value )
-{
- return read_range( begin, end, value );
-}
-
-void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value )
-{
- begin = read_range_or_throw( begin, end, value );
-}
-
-#ifndef BOOST_NO_STD_WSTRING
-
-bool json_spirit::read( const std::wstring& s, wmValue& value )
-{
- return read_string( s, value );
-}
-
-void json_spirit::read_or_throw( const std::wstring& s, wmValue& value )
-{
- read_string_or_throw( s, value );
-}
-
-bool json_spirit::read( std::wistream& is, wmValue& value )
-{
- return read_stream( is, value );
-}
-
-void json_spirit::read_or_throw( std::wistream& is, wmValue& value )
-{
- read_stream_or_throw( is, value );
-}
-
-bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value )
-{
- return read_range( begin, end, value );
-}
-
-void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value )
-{
- begin = read_range_or_throw( begin, end, value );
-}
-
-#endif
diff --git a/src/json/json_spirit_reader.h b/src/json/json_spirit_reader.h
deleted file mode 100644
index 96494a9789..0000000000
--- a/src/json/json_spirit_reader.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef JSON_SPIRIT_READER
-#define JSON_SPIRIT_READER
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-#include "json_spirit_value.h"
-#include "json_spirit_error_position.h"
-#include <iostream>
-
-namespace json_spirit
-{
- // functions to reads a JSON values
-
- bool read( const std::string& s, Value& value );
- bool read( std::istream& is, Value& value );
- bool read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value );
-
- void read_or_throw( const std::string& s, Value& value );
- void read_or_throw( std::istream& is, Value& value );
- void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value );
-
-#ifndef BOOST_NO_STD_WSTRING
-
- bool read( const std::wstring& s, wValue& value );
- bool read( std::wistream& is, wValue& value );
- bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value );
-
- void read_or_throw( const std::wstring& s, wValue& value );
- void read_or_throw( std::wistream& is, wValue& value );
- void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value );
-
-#endif
-
- bool read( const std::string& s, mValue& value );
- bool read( std::istream& is, mValue& value );
- bool read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value );
-
- void read_or_throw( const std::string& s, mValue& value );
- void read_or_throw( std::istream& is, mValue& value );
- void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value );
-
-#ifndef BOOST_NO_STD_WSTRING
-
- bool read( const std::wstring& s, wmValue& value );
- bool read( std::wistream& is, wmValue& value );
- bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value );
-
- void read_or_throw( const std::wstring& s, wmValue& value );
- void read_or_throw( std::wistream& is, wmValue& value );
- void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value );
-
-#endif
-}
-
-#endif
diff --git a/src/json/json_spirit_reader_template.h b/src/json/json_spirit_reader_template.h
deleted file mode 100644
index 47e3c1ca84..0000000000
--- a/src/json/json_spirit_reader_template.h
+++ /dev/null
@@ -1,612 +0,0 @@
-#ifndef JSON_SPIRIT_READER_TEMPLATE
-#define JSON_SPIRIT_READER_TEMPLATE
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#include "json_spirit_value.h"
-#include "json_spirit_error_position.h"
-
-//#define BOOST_SPIRIT_THREADSAFE // uncomment for multithreaded use, requires linking to boost.thread
-
-#include <boost/bind.hpp>
-#include <boost/function.hpp>
-#include <boost/version.hpp>
-
-#if BOOST_VERSION >= 103800
- #include <boost/spirit/include/classic_core.hpp>
- #include <boost/spirit/include/classic_confix.hpp>
- #include <boost/spirit/include/classic_escape_char.hpp>
- #include <boost/spirit/include/classic_multi_pass.hpp>
- #include <boost/spirit/include/classic_position_iterator.hpp>
- #define spirit_namespace boost::spirit::classic
-#else
- #include <boost/spirit/core.hpp>
- #include <boost/spirit/utility/confix.hpp>
- #include <boost/spirit/utility/escape_char.hpp>
- #include <boost/spirit/iterator/multi_pass.hpp>
- #include <boost/spirit/iterator/position_iterator.hpp>
- #define spirit_namespace boost::spirit
-#endif
-
-namespace json_spirit
-{
- const spirit_namespace::int_parser < int64_t > int64_p = spirit_namespace::int_parser < int64_t >();
- const spirit_namespace::uint_parser< uint64_t > uint64_p = spirit_namespace::uint_parser< uint64_t >();
-
- template< class Iter_type >
- bool is_eq( Iter_type first, Iter_type last, const char* c_str )
- {
- for( Iter_type i = first; i != last; ++i, ++c_str )
- {
- if( *c_str == 0 ) return false;
-
- if( *i != *c_str ) return false;
- }
-
- return true;
- }
-
- template< class Char_type >
- Char_type hex_to_num( const Char_type c )
- {
- if( ( c >= '0' ) && ( c <= '9' ) ) return c - '0';
- if( ( c >= 'a' ) && ( c <= 'f' ) ) return c - 'a' + 10;
- if( ( c >= 'A' ) && ( c <= 'F' ) ) return c - 'A' + 10;
- return 0;
- }
-
- template< class Char_type, class Iter_type >
- Char_type hex_str_to_char( Iter_type& begin )
- {
- const Char_type c1( *( ++begin ) );
- const Char_type c2( *( ++begin ) );
-
- return ( hex_to_num( c1 ) << 4 ) + hex_to_num( c2 );
- }
-
- template< class Char_type, class Iter_type >
- Char_type unicode_str_to_char( Iter_type& begin )
- {
- const Char_type c1( *( ++begin ) );
- const Char_type c2( *( ++begin ) );
- const Char_type c3( *( ++begin ) );
- const Char_type c4( *( ++begin ) );
-
- return ( hex_to_num( c1 ) << 12 ) +
- ( hex_to_num( c2 ) << 8 ) +
- ( hex_to_num( c3 ) << 4 ) +
- hex_to_num( c4 );
- }
-
- template< class String_type >
- void append_esc_char_and_incr_iter( String_type& s,
- typename String_type::const_iterator& begin,
- typename String_type::const_iterator end )
- {
- typedef typename String_type::value_type Char_type;
-
- const Char_type c2( *begin );
-
- switch( c2 )
- {
- case 't': s += '\t'; break;
- case 'b': s += '\b'; break;
- case 'f': s += '\f'; break;
- case 'n': s += '\n'; break;
- case 'r': s += '\r'; break;
- case '\\': s += '\\'; break;
- case '/': s += '/'; break;
- case '"': s += '"'; break;
- case 'x':
- {
- if( end - begin >= 3 ) // expecting "xHH..."
- {
- s += hex_str_to_char< Char_type >( begin );
- }
- break;
- }
- case 'u':
- {
- if( end - begin >= 5 ) // expecting "uHHHH..."
- {
- s += unicode_str_to_char< Char_type >( begin );
- }
- break;
- }
- }
- }
-
- template< class String_type >
- String_type substitute_esc_chars( typename String_type::const_iterator begin,
- typename String_type::const_iterator end )
- {
- typedef typename String_type::const_iterator Iter_type;
-
- if( end - begin < 2 ) return String_type( begin, end );
-
- String_type result;
-
- result.reserve( end - begin );
-
- const Iter_type end_minus_1( end - 1 );
-
- Iter_type substr_start = begin;
- Iter_type i = begin;
-
- for( ; i < end_minus_1; ++i )
- {
- if( *i == '\\' )
- {
- result.append( substr_start, i );
-
- ++i; // skip the '\'
-
- append_esc_char_and_incr_iter( result, i, end );
-
- substr_start = i + 1;
- }
- }
-
- result.append( substr_start, end );
-
- return result;
- }
-
- template< class String_type >
- String_type get_str_( typename String_type::const_iterator begin,
- typename String_type::const_iterator end )
- {
- assert( end - begin >= 2 );
-
- typedef typename String_type::const_iterator Iter_type;
-
- Iter_type str_without_quotes( ++begin );
- Iter_type end_without_quotes( --end );
-
- return substitute_esc_chars< String_type >( str_without_quotes, end_without_quotes );
- }
-
- inline std::string get_str( std::string::const_iterator begin, std::string::const_iterator end )
- {
- return get_str_< std::string >( begin, end );
- }
-
- inline std::wstring get_str( std::wstring::const_iterator begin, std::wstring::const_iterator end )
- {
- return get_str_< std::wstring >( begin, end );
- }
-
- template< class String_type, class Iter_type >
- String_type get_str( Iter_type begin, Iter_type end )
- {
- const String_type tmp( begin, end ); // convert multipass iterators to string iterators
-
- return get_str( tmp.begin(), tmp.end() );
- }
-
- // this class's methods get called by the spirit parse resulting
- // in the creation of a JSON object or array
- //
- // NB Iter_type could be a std::string iterator, wstring iterator, a position iterator or a multipass iterator
- //
- template< class Value_type, class Iter_type >
- class Semantic_actions
- {
- public:
-
- typedef typename Value_type::Config_type Config_type;
- typedef typename Config_type::String_type String_type;
- typedef typename Config_type::Object_type Object_type;
- typedef typename Config_type::Array_type Array_type;
- typedef typename String_type::value_type Char_type;
-
- Semantic_actions( Value_type& value )
- : value_( value )
- , current_p_( 0 )
- {
- }
-
- void begin_obj( Char_type c )
- {
- assert( c == '{' );
-
- begin_compound< Object_type >();
- }
-
- void end_obj( Char_type c )
- {
- assert( c == '}' );
-
- end_compound();
- }
-
- void begin_array( Char_type c )
- {
- assert( c == '[' );
-
- begin_compound< Array_type >();
- }
-
- void end_array( Char_type c )
- {
- assert( c == ']' );
-
- end_compound();
- }
-
- void new_name( Iter_type begin, Iter_type end )
- {
- assert( current_p_->type() == obj_type );
-
- name_ = get_str< String_type >( begin, end );
- }
-
- void new_str( Iter_type begin, Iter_type end )
- {
- add_to_current( get_str< String_type >( begin, end ) );
- }
-
- void new_true( Iter_type begin, Iter_type end )
- {
- assert( is_eq( begin, end, "true" ) );
-
- add_to_current( true );
- }
-
- void new_false( Iter_type begin, Iter_type end )
- {
- assert( is_eq( begin, end, "false" ) );
-
- add_to_current( false );
- }
-
- void new_null( Iter_type begin, Iter_type end )
- {
- assert( is_eq( begin, end, "null" ) );
-
- add_to_current( Value_type() );
- }
-
- void new_int( int64_t i )
- {
- add_to_current( i );
- }
-
- void new_uint64( uint64_t ui )
- {
- add_to_current( ui );
- }
-
- void new_real( double d )
- {
- add_to_current( d );
- }
-
- private:
-
- Semantic_actions& operator=( const Semantic_actions& );
- // to prevent "assignment operator could not be generated" warning
-
- Value_type* add_first( const Value_type& value )
- {
- assert( current_p_ == 0 );
-
- value_ = value;
- current_p_ = &value_;
- return current_p_;
- }
-
- template< class Array_or_obj >
- void begin_compound()
- {
- if( current_p_ == 0 )
- {
- add_first( Array_or_obj() );
- }
- else
- {
- stack_.push_back( current_p_ );
-
- Array_or_obj new_array_or_obj; // avoid copy by building new array or object in place
-
- current_p_ = add_to_current( new_array_or_obj );
- }
- }
-
- void end_compound()
- {
- if( current_p_ != &value_ )
- {
- current_p_ = stack_.back();
-
- stack_.pop_back();
- }
- }
-
- Value_type* add_to_current( const Value_type& value )
- {
- if( current_p_ == 0 )
- {
- return add_first( value );
- }
- else if( current_p_->type() == array_type )
- {
- current_p_->get_array().push_back( value );
-
- return &current_p_->get_array().back();
- }
-
- assert( current_p_->type() == obj_type );
-
- return &Config_type::add( current_p_->get_obj(), name_, value );
- }
-
- Value_type& value_; // this is the object or array that is being created
- Value_type* current_p_; // the child object or array that is currently being constructed
-
- std::vector< Value_type* > stack_; // previous child objects and arrays
-
- String_type name_; // of current name/value pair
- };
-
- template< typename Iter_type >
- void throw_error( spirit_namespace::position_iterator< Iter_type > i, const std::string& reason )
- {
- throw Error_position( i.get_position().line, i.get_position().column, reason );
- }
-
- template< typename Iter_type >
- void throw_error( Iter_type i, const std::string& reason )
- {
- throw reason;
- }
-
- // the spirit grammer
- //
- template< class Value_type, class Iter_type >
- class Json_grammer : public spirit_namespace::grammar< Json_grammer< Value_type, Iter_type > >
- {
- public:
-
- typedef Semantic_actions< Value_type, Iter_type > Semantic_actions_t;
-
- Json_grammer( Semantic_actions_t& semantic_actions )
- : actions_( semantic_actions )
- {
- }
-
- static void throw_not_value( Iter_type begin, Iter_type end )
- {
- throw_error( begin, "not a value" );
- }
-
- static void throw_not_array( Iter_type begin, Iter_type end )
- {
- throw_error( begin, "not an array" );
- }
-
- static void throw_not_object( Iter_type begin, Iter_type end )
- {
- throw_error( begin, "not an object" );
- }
-
- static void throw_not_pair( Iter_type begin, Iter_type end )
- {
- throw_error( begin, "not a pair" );
- }
-
- static void throw_not_colon( Iter_type begin, Iter_type end )
- {
- throw_error( begin, "no colon in pair" );
- }
-
- static void throw_not_string( Iter_type begin, Iter_type end )
- {
- throw_error( begin, "not a string" );
- }
-
- template< typename ScannerT >
- class definition
- {
- public:
-
- definition( const Json_grammer& self )
- {
- using namespace spirit_namespace;
-
- typedef typename Value_type::String_type::value_type Char_type;
-
- // first we convert the semantic action class methods to functors with the
- // parameter signature expected by spirit
-
- typedef boost::function< void( Char_type ) > Char_action;
- typedef boost::function< void( Iter_type, Iter_type ) > Str_action;
- typedef boost::function< void( double ) > Real_action;
- typedef boost::function< void( int64_t ) > Int_action;
- typedef boost::function< void( uint64_t ) > Uint64_action;
-
- Char_action begin_obj ( boost::bind( &Semantic_actions_t::begin_obj, &self.actions_, _1 ) );
- Char_action end_obj ( boost::bind( &Semantic_actions_t::end_obj, &self.actions_, _1 ) );
- Char_action begin_array( boost::bind( &Semantic_actions_t::begin_array, &self.actions_, _1 ) );
- Char_action end_array ( boost::bind( &Semantic_actions_t::end_array, &self.actions_, _1 ) );
- Str_action new_name ( boost::bind( &Semantic_actions_t::new_name, &self.actions_, _1, _2 ) );
- Str_action new_str ( boost::bind( &Semantic_actions_t::new_str, &self.actions_, _1, _2 ) );
- Str_action new_true ( boost::bind( &Semantic_actions_t::new_true, &self.actions_, _1, _2 ) );
- Str_action new_false ( boost::bind( &Semantic_actions_t::new_false, &self.actions_, _1, _2 ) );
- Str_action new_null ( boost::bind( &Semantic_actions_t::new_null, &self.actions_, _1, _2 ) );
- Real_action new_real ( boost::bind( &Semantic_actions_t::new_real, &self.actions_, _1 ) );
- Int_action new_int ( boost::bind( &Semantic_actions_t::new_int, &self.actions_, _1 ) );
- Uint64_action new_uint64 ( boost::bind( &Semantic_actions_t::new_uint64, &self.actions_, _1 ) );
-
- // actual grammer
-
- json_
- = value_ | eps_p[ &throw_not_value ]
- ;
-
- value_
- = string_[ new_str ]
- | number_
- | object_
- | array_
- | str_p( "true" ) [ new_true ]
- | str_p( "false" )[ new_false ]
- | str_p( "null" ) [ new_null ]
- ;
-
- object_
- = ch_p('{')[ begin_obj ]
- >> !members_
- >> ( ch_p('}')[ end_obj ] | eps_p[ &throw_not_object ] )
- ;
-
- members_
- = pair_ >> *( ',' >> pair_ )
- ;
-
- pair_
- = string_[ new_name ]
- >> ( ':' | eps_p[ &throw_not_colon ] )
- >> ( value_ | eps_p[ &throw_not_value ] )
- ;
-
- array_
- = ch_p('[')[ begin_array ]
- >> !elements_
- >> ( ch_p(']')[ end_array ] | eps_p[ &throw_not_array ] )
- ;
-
- elements_
- = value_ >> *( ',' >> value_ )
- ;
-
- string_
- = lexeme_d // this causes white space inside a string to be retained
- [
- confix_p
- (
- '"',
- *lex_escape_ch_p,
- '"'
- )
- ]
- ;
-
- number_
- = strict_real_p[ new_real ]
- | int64_p [ new_int ]
- | uint64_p [ new_uint64 ]
- ;
- }
-
- spirit_namespace::rule< ScannerT > json_, object_, members_, pair_, array_, elements_, value_, string_, number_;
-
- const spirit_namespace::rule< ScannerT >& start() const { return json_; }
- };
-
- private:
-
- Json_grammer& operator=( const Json_grammer& ); // to prevent "assignment operator could not be generated" warning
-
- Semantic_actions_t& actions_;
- };
-
- template< class Iter_type, class Value_type >
- Iter_type read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value )
- {
- Semantic_actions< Value_type, Iter_type > semantic_actions( value );
-
- const spirit_namespace::parse_info< Iter_type > info =
- spirit_namespace::parse( begin, end,
- Json_grammer< Value_type, Iter_type >( semantic_actions ) >> spirit_namespace::end_p,
- spirit_namespace::space_p );
-
- if( !info.hit )
- {
- throw_error( info.stop, "error" );
- }
-
- return info.stop;
- }
-
- template< class Iter_type, class Value_type >
- void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value )
- {
- typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t;
-
- const Posn_iter_t posn_begin( begin, end );
- const Posn_iter_t posn_end( end, end );
-
- read_range_or_throw( posn_begin, posn_end, value );
- }
-
- template< class Iter_type, class Value_type >
- bool read_range( Iter_type& begin, Iter_type end, Value_type& value )
- {
- try
- {
- begin = read_range_or_throw( begin, end, value );
-
- return true;
- }
- catch( ... )
- {
- return false;
- }
- }
-
- template< class String_type, class Value_type >
- void read_string_or_throw( const String_type& s, Value_type& value )
- {
- add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value );
- }
-
- template< class String_type, class Value_type >
- bool read_string( const String_type& s, Value_type& value )
- {
- typename String_type::const_iterator begin = s.begin();
-
- bool success = read_range( begin, s.end(), value );
- return success && begin == s.end();
- }
-
- template< class Istream_type >
- struct Multi_pass_iters
- {
- typedef typename Istream_type::char_type Char_type;
- typedef std::istream_iterator< Char_type, Char_type > istream_iter;
- typedef spirit_namespace::multi_pass< istream_iter > Mp_iter;
-
- Multi_pass_iters( Istream_type& is )
- {
- is.unsetf( std::ios::skipws );
-
- begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) );
- end_ = spirit_namespace::make_multi_pass( istream_iter() );
- }
-
- Mp_iter begin_;
- Mp_iter end_;
- };
-
- template< class Istream_type, class Value_type >
- bool read_stream( Istream_type& is, Value_type& value )
- {
- Multi_pass_iters< Istream_type > mp_iters( is );
-
- return read_range( mp_iters.begin_, mp_iters.end_, value );
- }
-
- template< class Istream_type, class Value_type >
- void read_stream_or_throw( Istream_type& is, Value_type& value )
- {
- const Multi_pass_iters< Istream_type > mp_iters( is );
-
- add_posn_iter_and_read_range_or_throw( mp_iters.begin_, mp_iters.end_, value );
- }
-}
-
-#endif
diff --git a/src/json/json_spirit_stream_reader.h b/src/json/json_spirit_stream_reader.h
deleted file mode 100644
index 7e59c9adc2..0000000000
--- a/src/json/json_spirit_stream_reader.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef JSON_SPIRIT_READ_STREAM
-#define JSON_SPIRIT_READ_STREAM
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-#include "json_spirit_reader_template.h"
-
-namespace json_spirit
-{
- // these classes allows you to read multiple top level contiguous values from a stream,
- // the normal stream read functions have a bug that prevent multiple top level values
- // from being read unless they are separated by spaces
-
- template< class Istream_type, class Value_type >
- class Stream_reader
- {
- public:
-
- Stream_reader( Istream_type& is )
- : iters_( is )
- {
- }
-
- bool read_next( Value_type& value )
- {
- return read_range( iters_.begin_, iters_.end_, value );
- }
-
- private:
-
- typedef Multi_pass_iters< Istream_type > Mp_iters;
-
- Mp_iters iters_;
- };
-
- template< class Istream_type, class Value_type >
- class Stream_reader_thrower
- {
- public:
-
- Stream_reader_thrower( Istream_type& is )
- : iters_( is )
- , posn_begin_( iters_.begin_, iters_.end_ )
- , posn_end_( iters_.end_, iters_.end_ )
- {
- }
-
- void read_next( Value_type& value )
- {
- posn_begin_ = read_range_or_throw( posn_begin_, posn_end_, value );
- }
-
- private:
-
- typedef Multi_pass_iters< Istream_type > Mp_iters;
- typedef spirit_namespace::position_iterator< typename Mp_iters::Mp_iter > Posn_iter_t;
-
- Mp_iters iters_;
- Posn_iter_t posn_begin_, posn_end_;
- };
-}
-
-#endif
diff --git a/src/json/json_spirit_utils.h b/src/json/json_spirit_utils.h
deleted file mode 100644
index 553e3b96a4..0000000000
--- a/src/json/json_spirit_utils.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef JSON_SPIRIT_UTILS
-#define JSON_SPIRIT_UTILS
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-#include "json_spirit_value.h"
-#include <map>
-
-namespace json_spirit
-{
- template< class Obj_t, class Map_t >
- void obj_to_map( const Obj_t& obj, Map_t& mp_obj )
- {
- mp_obj.clear();
-
- for( typename Obj_t::const_iterator i = obj.begin(); i != obj.end(); ++i )
- {
- mp_obj[ i->name_ ] = i->value_;
- }
- }
-
- template< class Obj_t, class Map_t >
- void map_to_obj( const Map_t& mp_obj, Obj_t& obj )
- {
- obj.clear();
-
- for( typename Map_t::const_iterator i = mp_obj.begin(); i != mp_obj.end(); ++i )
- {
- obj.push_back( typename Obj_t::value_type( i->first, i->second ) );
- }
- }
-
- typedef std::map< std::string, Value > Mapped_obj;
-
-#ifndef BOOST_NO_STD_WSTRING
- typedef std::map< std::wstring, wValue > wMapped_obj;
-#endif
-
- template< class Object_type, class String_type >
- const typename Object_type::value_type::Value_type& find_value( const Object_type& obj, const String_type& name )
- {
- for( typename Object_type::const_iterator i = obj.begin(); i != obj.end(); ++i )
- {
- if( i->name_ == name )
- {
- return i->value_;
- }
- }
-
- return Object_type::value_type::Value_type::null;
- }
-}
-
-#endif
diff --git a/src/json/json_spirit_value.cpp b/src/json/json_spirit_value.cpp
deleted file mode 100644
index 44d2f06a01..0000000000
--- a/src/json/json_spirit_value.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-/* Copyright (c) 2007 John W Wilkinson
-
- This source code can be used for any purpose as long as
- this comment is retained. */
-
-// json spirit version 2.00
-
-#include "json_spirit_value.h"
diff --git a/src/json/json_spirit_value.h b/src/json/json_spirit_value.h
deleted file mode 100644
index 13cc89210c..0000000000
--- a/src/json/json_spirit_value.h
+++ /dev/null
@@ -1,534 +0,0 @@
-#ifndef JSON_SPIRIT_VALUE
-#define JSON_SPIRIT_VALUE
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-#include <vector>
-#include <map>
-#include <string>
-#include <cassert>
-#include <sstream>
-#include <stdexcept>
-#include <stdint.h>
-#include <boost/config.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/variant.hpp>
-
-namespace json_spirit
-{
- enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type };
- static const char* Value_type_name[]={"obj", "array", "str", "bool", "int", "real", "null"};
-
- template< class Config > // Config determines whether the value uses std::string or std::wstring and
- // whether JSON Objects are represented as vectors or maps
- class Value_impl
- {
- public:
-
- typedef Config Config_type;
- typedef typename Config::String_type String_type;
- typedef typename Config::Object_type Object;
- typedef typename Config::Array_type Array;
- typedef typename String_type::const_pointer Const_str_ptr; // eg const char*
-
- Value_impl(); // creates null value
- Value_impl( Const_str_ptr value );
- Value_impl( const String_type& value );
- Value_impl( const Object& value );
- Value_impl( const Array& value );
- Value_impl( bool value );
- Value_impl( int value );
- Value_impl( int64_t value );
- Value_impl( uint64_t value );
- Value_impl( double value );
-
- Value_impl( const Value_impl& other );
-
- bool operator==( const Value_impl& lhs ) const;
-
- Value_impl& operator=( const Value_impl& lhs );
-
- Value_type type() const;
-
- bool is_uint64() const;
- bool is_null() const;
-
- const String_type& get_str() const;
- const Object& get_obj() const;
- const Array& get_array() const;
- bool get_bool() const;
- int get_int() const;
- int64_t get_int64() const;
- uint64_t get_uint64() const;
- double get_real() const;
-
- Object& get_obj();
- Array& get_array();
-
- template< typename T > T get_value() const; // example usage: int i = value.get_value< int >();
- // or double d = value.get_value< double >();
-
- static const Value_impl null;
-
- private:
-
- void check_type( const Value_type vtype ) const;
-
- typedef boost::variant< String_type,
- boost::recursive_wrapper< Object >, boost::recursive_wrapper< Array >,
- bool, int64_t, double > Variant;
-
- Value_type type_;
- Variant v_;
- bool is_uint64_;
- };
-
- // vector objects
-
- template< class Config >
- struct Pair_impl
- {
- typedef typename Config::String_type String_type;
- typedef typename Config::Value_type Value_type;
-
- Pair_impl( const String_type& name, const Value_type& value );
-
- bool operator==( const Pair_impl& lhs ) const;
-
- String_type name_;
- Value_type value_;
- };
-
- template< class String >
- struct Config_vector
- {
- typedef String String_type;
- typedef Value_impl< Config_vector > Value_type;
- typedef Pair_impl < Config_vector > Pair_type;
- typedef std::vector< Value_type > Array_type;
- typedef std::vector< Pair_type > Object_type;
-
- static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value )
- {
- obj.push_back( Pair_type( name , value ) );
-
- return obj.back().value_;
- }
-
- static String_type get_name( const Pair_type& pair )
- {
- return pair.name_;
- }
-
- static Value_type get_value( const Pair_type& pair )
- {
- return pair.value_;
- }
- };
-
- // typedefs for ASCII
-
- typedef Config_vector< std::string > Config;
-
- typedef Config::Value_type Value;
- typedef Config::Pair_type Pair;
- typedef Config::Object_type Object;
- typedef Config::Array_type Array;
-
- // typedefs for Unicode
-
-#ifndef BOOST_NO_STD_WSTRING
-
- typedef Config_vector< std::wstring > wConfig;
-
- typedef wConfig::Value_type wValue;
- typedef wConfig::Pair_type wPair;
- typedef wConfig::Object_type wObject;
- typedef wConfig::Array_type wArray;
-#endif
-
- // map objects
-
- template< class String >
- struct Config_map
- {
- typedef String String_type;
- typedef Value_impl< Config_map > Value_type;
- typedef std::vector< Value_type > Array_type;
- typedef std::map< String_type, Value_type > Object_type;
- typedef typename Object_type::value_type Pair_type;
-
- static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value )
- {
- return obj[ name ] = value;
- }
-
- static String_type get_name( const Pair_type& pair )
- {
- return pair.first;
- }
-
- static Value_type get_value( const Pair_type& pair )
- {
- return pair.second;
- }
- };
-
- // typedefs for ASCII
-
- typedef Config_map< std::string > mConfig;
-
- typedef mConfig::Value_type mValue;
- typedef mConfig::Object_type mObject;
- typedef mConfig::Array_type mArray;
-
- // typedefs for Unicode
-
-#ifndef BOOST_NO_STD_WSTRING
-
- typedef Config_map< std::wstring > wmConfig;
-
- typedef wmConfig::Value_type wmValue;
- typedef wmConfig::Object_type wmObject;
- typedef wmConfig::Array_type wmArray;
-
-#endif
-
- ///////////////////////////////////////////////////////////////////////////////////////////////
- //
- // implementation
-
- template< class Config >
- const Value_impl< Config > Value_impl< Config >::null;
-
- template< class Config >
- Value_impl< Config >::Value_impl()
- : type_( null_type )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( const Const_str_ptr value )
- : type_( str_type )
- , v_( String_type( value ) )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( const String_type& value )
- : type_( str_type )
- , v_( value )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( const Object& value )
- : type_( obj_type )
- , v_( value )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( const Array& value )
- : type_( array_type )
- , v_( value )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( bool value )
- : type_( bool_type )
- , v_( value )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( int value )
- : type_( int_type )
- , v_( static_cast< int64_t >( value ) )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( int64_t value )
- : type_( int_type )
- , v_( value )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( uint64_t value )
- : type_( int_type )
- , v_( static_cast< int64_t >( value ) )
- , is_uint64_( true )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( double value )
- : type_( real_type )
- , v_( value )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( const Value_impl< Config >& other )
- : type_( other.type() )
- , v_( other.v_ )
- , is_uint64_( other.is_uint64_ )
- {
- }
-
- template< class Config >
- Value_impl< Config >& Value_impl< Config >::operator=( const Value_impl& lhs )
- {
- Value_impl tmp( lhs );
-
- std::swap( type_, tmp.type_ );
- std::swap( v_, tmp.v_ );
- std::swap( is_uint64_, tmp.is_uint64_ );
-
- return *this;
- }
-
- template< class Config >
- bool Value_impl< Config >::operator==( const Value_impl& lhs ) const
- {
- if( this == &lhs ) return true;
-
- if( type() != lhs.type() ) return false;
-
- return v_ == lhs.v_;
- }
-
- template< class Config >
- Value_type Value_impl< Config >::type() const
- {
- return type_;
- }
-
- template< class Config >
- bool Value_impl< Config >::is_uint64() const
- {
- return is_uint64_;
- }
-
- template< class Config >
- bool Value_impl< Config >::is_null() const
- {
- return type() == null_type;
- }
-
- template< class Config >
- void Value_impl< Config >::check_type( const Value_type vtype ) const
- {
- if( type() != vtype )
- {
- std::ostringstream os;
-
- ///// Bitcoin: Tell the types by name instead of by number
- os << "value is type " << Value_type_name[type()] << ", expected " << Value_type_name[vtype];
-
- throw std::runtime_error( os.str() );
- }
- }
-
- template< class Config >
- const typename Config::String_type& Value_impl< Config >::get_str() const
- {
- check_type( str_type );
-
- return *boost::get< String_type >( &v_ );
- }
-
- template< class Config >
- const typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() const
- {
- check_type( obj_type );
-
- return *boost::get< Object >( &v_ );
- }
-
- template< class Config >
- const typename Value_impl< Config >::Array& Value_impl< Config >::get_array() const
- {
- check_type( array_type );
-
- return *boost::get< Array >( &v_ );
- }
-
- template< class Config >
- bool Value_impl< Config >::get_bool() const
- {
- check_type( bool_type );
-
- return boost::get< bool >( v_ );
- }
-
- template< class Config >
- int Value_impl< Config >::get_int() const
- {
- check_type( int_type );
-
- return static_cast< int >( get_int64() );
- }
-
- template< class Config >
- int64_t Value_impl< Config >::get_int64() const
- {
- check_type( int_type );
-
- return boost::get< int64_t >( v_ );
- }
-
- template< class Config >
- uint64_t Value_impl< Config >::get_uint64() const
- {
- check_type( int_type );
-
- return static_cast< uint64_t >( get_int64() );
- }
-
- template< class Config >
- double Value_impl< Config >::get_real() const
- {
- if( type() == int_type )
- {
- return is_uint64() ? static_cast< double >( get_uint64() )
- : static_cast< double >( get_int64() );
- }
-
- check_type( real_type );
-
- return boost::get< double >( v_ );
- }
-
- template< class Config >
- typename Value_impl< Config >::Object& Value_impl< Config >::get_obj()
- {
- check_type( obj_type );
-
- return *boost::get< Object >( &v_ );
- }
-
- template< class Config >
- typename Value_impl< Config >::Array& Value_impl< Config >::get_array()
- {
- check_type( array_type );
-
- return *boost::get< Array >( &v_ );
- }
-
- template< class Config >
- Pair_impl< Config >::Pair_impl( const String_type& name, const Value_type& value )
- : name_( name )
- , value_( value )
- {
- }
-
- template< class Config >
- bool Pair_impl< Config >::operator==( const Pair_impl< Config >& lhs ) const
- {
- if( this == &lhs ) return true;
-
- return ( name_ == lhs.name_ ) && ( value_ == lhs.value_ );
- }
-
- // converts a C string, ie. 8 bit char array, to a string object
- //
- template < class String_type >
- String_type to_str( const char* c_str )
- {
- String_type result;
-
- for( const char* p = c_str; *p != 0; ++p )
- {
- result += *p;
- }
-
- return result;
- }
-
- //
-
- namespace internal_
- {
- template< typename T >
- struct Type_to_type
- {
- };
-
- template< class Value >
- int get_value( const Value& value, Type_to_type< int > )
- {
- return value.get_int();
- }
-
- template< class Value >
- int64_t get_value( const Value& value, Type_to_type< int64_t > )
- {
- return value.get_int64();
- }
-
- template< class Value >
- uint64_t get_value( const Value& value, Type_to_type< uint64_t > )
- {
- return value.get_uint64();
- }
-
- template< class Value >
- double get_value( const Value& value, Type_to_type< double > )
- {
- return value.get_real();
- }
-
- template< class Value >
- typename Value::String_type get_value( const Value& value, Type_to_type< typename Value::String_type > )
- {
- return value.get_str();
- }
-
- template< class Value >
- typename Value::Array get_value( const Value& value, Type_to_type< typename Value::Array > )
- {
- return value.get_array();
- }
-
- template< class Value >
- typename Value::Object get_value( const Value& value, Type_to_type< typename Value::Object > )
- {
- return value.get_obj();
- }
-
- template< class Value >
- bool get_value( const Value& value, Type_to_type< bool > )
- {
- return value.get_bool();
- }
- }
-
- template< class Config >
- template< typename T >
- T Value_impl< Config >::get_value() const
- {
- return internal_::get_value( *this, internal_::Type_to_type< T >() );
- }
-}
-
-#endif
diff --git a/src/json/json_spirit_writer.cpp b/src/json/json_spirit_writer.cpp
deleted file mode 100644
index d24a632cf3..0000000000
--- a/src/json/json_spirit_writer.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#include "json_spirit_writer.h"
-#include "json_spirit_writer_template.h"
-
-void json_spirit::write( const Value& value, std::ostream& os )
-{
- write_stream( value, os, false );
-}
-
-void json_spirit::write_formatted( const Value& value, std::ostream& os )
-{
- write_stream( value, os, true );
-}
-
-std::string json_spirit::write( const Value& value )
-{
- return write_string( value, false );
-}
-
-std::string json_spirit::write_formatted( const Value& value )
-{
- return write_string( value, true );
-}
-
-#ifndef BOOST_NO_STD_WSTRING
-
-void json_spirit::write( const wValue& value, std::wostream& os )
-{
- write_stream( value, os, false );
-}
-
-void json_spirit::write_formatted( const wValue& value, std::wostream& os )
-{
- write_stream( value, os, true );
-}
-
-std::wstring json_spirit::write( const wValue& value )
-{
- return write_string( value, false );
-}
-
-std::wstring json_spirit::write_formatted( const wValue& value )
-{
- return write_string( value, true );
-}
-
-#endif
-
-void json_spirit::write( const mValue& value, std::ostream& os )
-{
- write_stream( value, os, false );
-}
-
-void json_spirit::write_formatted( const mValue& value, std::ostream& os )
-{
- write_stream( value, os, true );
-}
-
-std::string json_spirit::write( const mValue& value )
-{
- return write_string( value, false );
-}
-
-std::string json_spirit::write_formatted( const mValue& value )
-{
- return write_string( value, true );
-}
-
-#ifndef BOOST_NO_STD_WSTRING
-
-void json_spirit::write( const wmValue& value, std::wostream& os )
-{
- write_stream( value, os, false );
-}
-
-void json_spirit::write_formatted( const wmValue& value, std::wostream& os )
-{
- write_stream( value, os, true );
-}
-
-std::wstring json_spirit::write( const wmValue& value )
-{
- return write_string( value, false );
-}
-
-std::wstring json_spirit::write_formatted( const wmValue& value )
-{
- return write_string( value, true );
-}
-
-#endif
diff --git a/src/json/json_spirit_writer.h b/src/json/json_spirit_writer.h
deleted file mode 100644
index 52e14068e7..0000000000
--- a/src/json/json_spirit_writer.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef JSON_SPIRIT_WRITER
-#define JSON_SPIRIT_WRITER
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-#include "json_spirit_value.h"
-#include <iostream>
-
-namespace json_spirit
-{
- // functions to convert JSON Values to text,
- // the "formatted" versions add whitespace to format the output nicely
-
- void write ( const Value& value, std::ostream& os );
- void write_formatted( const Value& value, std::ostream& os );
- std::string write ( const Value& value );
- std::string write_formatted( const Value& value );
-
-#ifndef BOOST_NO_STD_WSTRING
-
- void write ( const wValue& value, std::wostream& os );
- void write_formatted( const wValue& value, std::wostream& os );
- std::wstring write ( const wValue& value );
- std::wstring write_formatted( const wValue& value );
-
-#endif
-
- void write ( const mValue& value, std::ostream& os );
- void write_formatted( const mValue& value, std::ostream& os );
- std::string write ( const mValue& value );
- std::string write_formatted( const mValue& value );
-
-#ifndef BOOST_NO_STD_WSTRING
-
- void write ( const wmValue& value, std::wostream& os );
- void write_formatted( const wmValue& value, std::wostream& os );
- std::wstring write ( const wmValue& value );
- std::wstring write_formatted( const wmValue& value );
-
-#endif
-}
-
-#endif
diff --git a/src/json/json_spirit_writer_template.h b/src/json/json_spirit_writer_template.h
deleted file mode 100644
index 6b4978a1ff..0000000000
--- a/src/json/json_spirit_writer_template.h
+++ /dev/null
@@ -1,249 +0,0 @@
-#ifndef JSON_SPIRIT_WRITER_TEMPLATE
-#define JSON_SPIRIT_WRITER_TEMPLATE
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#include "json_spirit_value.h"
-
-#include <cassert>
-#include <sstream>
-#include <iomanip>
-
-namespace json_spirit
-{
- inline char to_hex_char( unsigned int c )
- {
- assert( c <= 0xF );
-
- const char ch = static_cast< char >( c );
-
- if( ch < 10 ) return '0' + ch;
-
- return 'A' - 10 + ch;
- }
-
- template< class String_type >
- String_type non_printable_to_string( unsigned int c )
- {
- // Silence the warning: typedef ‘Char_type’ locally defined but not used [-Wunused-local-typedefs]
- // typedef typename String_type::value_type Char_type;
-
- String_type result( 6, '\\' );
-
- result[1] = 'u';
-
- result[ 5 ] = to_hex_char( c & 0x000F ); c >>= 4;
- result[ 4 ] = to_hex_char( c & 0x000F ); c >>= 4;
- result[ 3 ] = to_hex_char( c & 0x000F ); c >>= 4;
- result[ 2 ] = to_hex_char( c & 0x000F );
-
- return result;
- }
-
- template< typename Char_type, class String_type >
- bool add_esc_char( Char_type c, String_type& s )
- {
- switch( c )
- {
- case '"': s += to_str< String_type >( "\\\"" ); return true;
- case '\\': s += to_str< String_type >( "\\\\" ); return true;
- case '\b': s += to_str< String_type >( "\\b" ); return true;
- case '\f': s += to_str< String_type >( "\\f" ); return true;
- case '\n': s += to_str< String_type >( "\\n" ); return true;
- case '\r': s += to_str< String_type >( "\\r" ); return true;
- case '\t': s += to_str< String_type >( "\\t" ); return true;
- }
-
- return false;
- }
-
- template< class String_type >
- String_type add_esc_chars( const String_type& s )
- {
- typedef typename String_type::const_iterator Iter_type;
- typedef typename String_type::value_type Char_type;
-
- String_type result;
-
- const Iter_type end( s.end() );
-
- for( Iter_type i = s.begin(); i != end; ++i )
- {
- const Char_type c( *i );
-
- if( add_esc_char( c, result ) ) continue;
-
- const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c );
-
- if( iswprint( unsigned_c ) )
- {
- result += c;
- }
- else
- {
- result += non_printable_to_string< String_type >( unsigned_c );
- }
- }
-
- return result;
- }
-
- // this class generates the JSON text,
- // it keeps track of the indentation level etc.
- //
- template< class Value_type, class Ostream_type >
- class Generator
- {
- typedef typename Value_type::Config_type Config_type;
- typedef typename Config_type::String_type String_type;
- typedef typename Config_type::Object_type Object_type;
- typedef typename Config_type::Array_type Array_type;
- typedef typename String_type::value_type Char_type;
- typedef typename Object_type::value_type Obj_member_type;
-
- public:
-
- Generator( const Value_type& value, Ostream_type& os, bool pretty )
- : os_( os )
- , indentation_level_( 0 )
- , pretty_( pretty )
- {
- output( value );
- }
-
- private:
-
- void output( const Value_type& value )
- {
- switch( value.type() )
- {
- case obj_type: output( value.get_obj() ); break;
- case array_type: output( value.get_array() ); break;
- case str_type: output( value.get_str() ); break;
- case bool_type: output( value.get_bool() ); break;
- case int_type: output_int( value ); break;
-
- /// Bitcoin: Added std::fixed and changed precision from 16 to 8
- case real_type: os_ << std::showpoint << std::fixed << std::setprecision(8)
- << value.get_real(); break;
-
- case null_type: os_ << "null"; break;
- default: assert( false );
- }
- }
-
- void output( const Object_type& obj )
- {
- output_array_or_obj( obj, '{', '}' );
- }
-
- void output( const Array_type& arr )
- {
- output_array_or_obj( arr, '[', ']' );
- }
-
- void output( const Obj_member_type& member )
- {
- output( Config_type::get_name( member ) ); space();
- os_ << ':'; space();
- output( Config_type::get_value( member ) );
- }
-
- void output_int( const Value_type& value )
- {
- if( value.is_uint64() )
- {
- os_ << value.get_uint64();
- }
- else
- {
- os_ << value.get_int64();
- }
- }
-
- void output( const String_type& s )
- {
- os_ << '"' << add_esc_chars( s ) << '"';
- }
-
- void output( bool b )
- {
- os_ << to_str< String_type >( b ? "true" : "false" );
- }
-
- template< class T >
- void output_array_or_obj( const T& t, Char_type start_char, Char_type end_char )
- {
- os_ << start_char; new_line();
-
- ++indentation_level_;
-
- for( typename T::const_iterator i = t.begin(); i != t.end(); ++i )
- {
- indent(); output( *i );
-
- typename T::const_iterator next = i;
-
- if( ++next != t.end())
- {
- os_ << ',';
- }
-
- new_line();
- }
-
- --indentation_level_;
-
- indent(); os_ << end_char;
- }
-
- void indent()
- {
- if( !pretty_ ) return;
-
- for( int i = 0; i < indentation_level_; ++i )
- {
- os_ << " ";
- }
- }
-
- void space()
- {
- if( pretty_ ) os_ << ' ';
- }
-
- void new_line()
- {
- if( pretty_ ) os_ << '\n';
- }
-
- Generator& operator=( const Generator& ); // to prevent "assignment operator could not be generated" warning
-
- Ostream_type& os_;
- int indentation_level_;
- bool pretty_;
- };
-
- template< class Value_type, class Ostream_type >
- void write_stream( const Value_type& value, Ostream_type& os, bool pretty )
- {
- Generator< Value_type, Ostream_type >( value, os, pretty );
- }
-
- template< class Value_type >
- typename Value_type::String_type write_string( const Value_type& value, bool pretty )
- {
- typedef typename Value_type::String_type::value_type Char_type;
-
- std::basic_ostringstream< Char_type > os;
-
- write_stream( value, os, pretty );
-
- return os.str();
- }
-}
-
-#endif
diff --git a/src/main.cpp b/src/main.cpp
index dc9585b021..a3e43e0cc5 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -61,6 +61,7 @@ bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = true;
size_t nCoinCacheUsage = 5000 * 300;
uint64_t nPruneTarget = 0;
+bool fAlerts = DEFAULT_ALERTS;
/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
CFeeRate minRelayTxFee = CFeeRate(1000);
@@ -694,7 +695,7 @@ bool CheckFinalTx(const CTransaction &tx)
/**
* Check transaction inputs to mitigate two
* potential denial-of-service attacks:
- *
+ *
* 1. scriptSigs with extra data stuffed into them,
* not consumed by scriptPubKey (or P2SH script)
* 2. P2SH scripts with a crazy number of expensive
@@ -1396,22 +1397,21 @@ bool CScriptCheck::operator()() {
return true;
}
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks)
+int GetSpendHeight(const CCoinsViewCache& inputs)
{
- if (!tx.IsCoinBase())
- {
- if (pvChecks)
- pvChecks->reserve(tx.vin.size());
+ LOCK(cs_main);
+ CBlockIndex* pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
+ return pindexPrev->nHeight + 1;
+}
+namespace Consensus {
+bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight)
+{
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
// for an attacker to attempt to split the network.
if (!inputs.HaveInputs(tx))
return state.Invalid(error("CheckInputs(): %s inputs unavailable", tx.GetHash().ToString()));
- // While checking, GetBestBlock() refers to the parent block.
- // This is also true for mempool checks.
- CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
- int nSpendHeight = pindexPrev->nHeight + 1;
CAmount nValueIn = 0;
CAmount nFees = 0;
for (unsigned int i = 0; i < tx.vin.size(); i++)
@@ -1450,6 +1450,19 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
if (!MoneyRange(nFees))
return state.DoS(100, error("CheckInputs(): nFees out of range"),
REJECT_INVALID, "bad-txns-fee-outofrange");
+ return true;
+}
+}// namespace Consensus
+
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks)
+{
+ if (!tx.IsCoinBase())
+ {
+ if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs)))
+ return false;
+
+ if (pvChecks)
+ pvChecks->reserve(tx.vin.size());
// The first loop above does all the inexpensive checks.
// Only if ALL inputs pass do we perform expensive ECDSA signature checks.
@@ -1712,9 +1725,10 @@ void ThreadScriptCheck() {
// we're being fed a bad chain (blocks being generated much
// too slowly or too quickly).
//
-void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CChain& chain, int64_t nPowTargetSpacing)
+void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader,
+ int64_t nPowTargetSpacing)
{
- if (initialDownloadCheck()) return;
+ if (bestHeader == NULL || initialDownloadCheck()) return;
static int64_t lastAlertTime = 0;
int64_t now = GetAdjustedTime();
@@ -1730,10 +1744,13 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const
int64_t startTime = GetAdjustedTime()-SPAN_SECONDS;
LOCK(cs);
- int h = chain.Height();
- while (h > 0 && chain[h]->GetBlockTime() >= startTime)
- --h;
- int nBlocks = chain.Height()-h;
+ const CBlockIndex* i = bestHeader;
+ int nBlocks = 0;
+ while (i->GetBlockTime() >= startTime) {
+ ++nBlocks;
+ i = i->pprev;
+ if (i == NULL) return; // Ran out of chain, we must not be fully sync'ed
+ }
// How likely is it to find that many by chance?
double p = boost::math::pdf(poisson, nBlocks);
@@ -1791,7 +1808,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return true;
}
- bool fScriptChecks = (!fCheckpointsEnabled || pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()));
+ bool fScriptChecks = true;
+ if (fCheckpointsEnabled) {
+ CBlockIndex *pindexLastCheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints());
+ if (pindexLastCheckpoint && pindexLastCheckpoint->GetAncestor(pindex->nHeight) == pindex) {
+ // This block is an ancestor of a checkpoint: disable script checks
+ fScriptChecks = false;
+ }
+ }
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
// unless those are already completely spent.
@@ -2149,7 +2173,7 @@ static int64_t nTimeFlush = 0;
static int64_t nTimeChainState = 0;
static int64_t nTimePostConnect = 0;
-/**
+/**
* Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock
* corresponding to pindexNew, to bypass loading it again from disk.
*/
@@ -2713,18 +2737,23 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
return true;
}
-bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev)
+static bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidationState& state, const CChainParams& chainparams, const uint256& hash)
{
- const CChainParams& chainParams = Params();
- const Consensus::Params& consensusParams = chainParams.GetConsensus();
- uint256 hash = block.GetHash();
- if (hash == consensusParams.hashGenesisBlock)
+ if (*pindexPrev->phashBlock == chainparams.GetConsensus().hashGenesisBlock)
return true;
- assert(pindexPrev);
-
int nHeight = pindexPrev->nHeight+1;
+ // Don't accept any forks from the main chain prior to last checkpoint
+ CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints());
+ if (pcheckpoint && nHeight < pcheckpoint->nHeight)
+ return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight));
+ return true;
+}
+
+bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev)
+{
+ const Consensus::Params& consensusParams = Params().GetConsensus();
// Check proof of work
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
return state.DoS(100, error("%s: incorrect proof of work", __func__),
@@ -2735,19 +2764,6 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
return state.Invalid(error("%s: block's timestamp is too early", __func__),
REJECT_INVALID, "time-too-old");
- if(fCheckpointsEnabled)
- {
- // Check that the block chain matches the known block chain up to a checkpoint
- if (!Checkpoints::CheckBlock(chainParams.Checkpoints(), nHeight, hash))
- return state.DoS(100, error("%s: rejected by checkpoint lock-in at %d", __func__, nHeight),
- REJECT_CHECKPOINT, "checkpoint mismatch");
-
- // Don't accept any forks from the main chain prior to last checkpoint
- CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainParams.Checkpoints());
- if (pcheckpoint && nHeight < pcheckpoint->nHeight)
- return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight));
- }
-
// Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
if (block.nVersion < 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams))
return state.Invalid(error("%s: rejected nVersion=1 block", __func__),
@@ -2817,6 +2833,9 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
if (pindexPrev->nStatus & BLOCK_FAILED_MASK)
return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
}
+ assert(pindexPrev);
+ if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, hash))
+ return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str());
if (!ContextualCheckBlockHeader(block, state, pindexPrev))
return false;
@@ -2932,8 +2951,11 @@ bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool
bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex * const pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot)
{
+ const CChainParams& chainparams = Params();
AssertLockHeld(cs_main);
- assert(pindexPrev == chainActive.Tip());
+ assert(pindexPrev && pindexPrev == chainActive.Tip());
+ if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, block.GetHash()))
+ return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str());
CCoinsViewCache viewNew(pcoinsTip);
CBlockIndex indexDummy(block);
@@ -3041,9 +3063,9 @@ void FindFilesToPrune(std::set<int>& setFilesToPrune)
if (nCurrentUsage + nBuffer < nPruneTarget) // are we below our target?
break;
- // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip
+ // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning
if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune)
- break;
+ continue;
PruneOneBlockFile(fileNumber);
// Queue up the files for removal
@@ -3697,7 +3719,7 @@ void static CheckBlockIndex()
// CAlert
//
-string GetWarnings(string strFor)
+std::string GetWarnings(const std::string& strFor)
{
int nPriority = 0;
string strStatusBar;
@@ -4321,7 +4343,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
mempool.check(pcoinsTip);
RelayTransaction(tx);
vWorkQueue.push_back(inv.hash);
- vEraseQueue.push_back(inv.hash);
LogPrint("mempool", "AcceptToMemoryPool: peer=%d %s: accepted %s (poolsz %u)\n",
pfrom->id, pfrom->cleanSubVer,
@@ -4348,7 +4369,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// anyone relaying LegitTxX banned)
CValidationState stateDummy;
- vEraseQueue.push_back(orphanHash);
if (setMisbehaving.count(fromPeer))
continue;
@@ -4357,6 +4377,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
RelayTransaction(orphanTx);
vWorkQueue.push_back(orphanHash);
+ vEraseQueue.push_back(orphanHash);
}
else if (!fMissingInputs2)
{
@@ -4368,8 +4389,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
setMisbehaving.insert(fromPeer);
LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString());
}
- // too-little-fee orphan
+ // Has inputs but not accepted to mempool
+ // Probably non-standard or insufficient fee/priority
LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString());
+ vEraseQueue.push_back(orphanHash);
}
mempool.check(pcoinsTip);
}
@@ -4605,7 +4628,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "alert")
+ else if (fAlerts && strCommand == "alert")
{
CAlert alert;
vRecv >> alert;
diff --git a/src/main.h b/src/main.h
index 669ea7128a..4e2efaada0 100644
--- a/src/main.h
+++ b/src/main.h
@@ -52,6 +52,8 @@ static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000;
static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0;
/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/
static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000;
+/** Default for accepting alerts from the P2P network. */
+static const bool DEFAULT_ALERTS = true;
/** The maximum size for transactions we're willing to relay/mine */
static const unsigned int MAX_STANDARD_TX_SIZE = 100000;
/** Maximum number of signature check operations in an IsStandard() P2SH script */
@@ -113,6 +115,7 @@ extern bool fCheckBlockIndex;
extern bool fCheckpointsEnabled;
extern size_t nCoinCacheUsage;
extern CFeeRate minRelayTxFee;
+extern bool fAlerts;
/** Best header we've seen so far (used for getheaders queries' starting points). */
extern CBlockIndex *pindexBestHeader;
@@ -186,11 +189,11 @@ bool SendMessages(CNode* pto, bool fSendTrickle);
/** Run an instance of the script checking thread */
void ThreadScriptCheck();
/** Try to detect Partition (network isolation) attacks against us */
-void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CChain& chain, int64_t nPowTargetSpacing);
+void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing);
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
bool IsInitialBlockDownload();
/** Format a string that describes several potential problems detected by the core */
-std::string GetWarnings(std::string strFor);
+std::string GetWarnings(const std::string& strFor);
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false);
/** Find the best known block, and make it the tip of the block chain */
@@ -487,4 +490,11 @@ extern CCoinsViewCache *pcoinsTip;
/** Global variable that points to the active block tree (protected by cs_main) */
extern CBlockTreeDB *pblocktree;
+/**
+ * Return the spend height, which is one more than the inputs.GetBestBlock().
+ * While checking, GetBestBlock() refers to the parent block. (protected by cs_main)
+ * This is also true for mempool checks.
+ */
+int GetSpendHeight(const CCoinsViewCache& inputs);
+
#endif // BITCOIN_MAIN_H
diff --git a/src/net.cpp b/src/net.cpp
index 3908be6824..0511256e55 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -107,7 +107,7 @@ boost::condition_variable messageHandlerCondition;
static CNodeSignals g_signals;
CNodeSignals& GetNodeSignals() { return g_signals; }
-void AddOneShot(string strDest)
+void AddOneShot(const std::string& strDest)
{
LOCK(cs_vOneShots);
vOneShots.push_back(strDest);
@@ -332,6 +332,15 @@ CNode* FindNode(const CNetAddr& ip)
return NULL;
}
+CNode* FindNode(const CSubNet& subNet)
+{
+ LOCK(cs_vNodes);
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (subNet.Match((CNetAddr)pnode->addr))
+ return (pnode);
+ return NULL;
+}
+
CNode* FindNode(const std::string& addrName)
{
LOCK(cs_vNodes);
@@ -434,11 +443,12 @@ void CNode::PushVersion()
-std::map<CNetAddr, int64_t> CNode::setBanned;
+std::map<CSubNet, int64_t> CNode::setBanned;
CCriticalSection CNode::cs_setBanned;
void CNode::ClearBanned()
{
+ LOCK(cs_setBanned);
setBanned.clear();
}
@@ -447,7 +457,24 @@ bool CNode::IsBanned(CNetAddr ip)
bool fResult = false;
{
LOCK(cs_setBanned);
- std::map<CNetAddr, int64_t>::iterator i = setBanned.find(ip);
+ for (std::map<CSubNet, int64_t>::iterator it = setBanned.begin(); it != setBanned.end(); it++)
+ {
+ CSubNet subNet = (*it).first;
+ int64_t t = (*it).second;
+
+ if(subNet.Match(ip) && GetTime() < t)
+ fResult = true;
+ }
+ }
+ return fResult;
+}
+
+bool CNode::IsBanned(CSubNet subnet)
+{
+ bool fResult = false;
+ {
+ LOCK(cs_setBanned);
+ std::map<CSubNet, int64_t>::iterator i = setBanned.find(subnet);
if (i != setBanned.end())
{
int64_t t = (*i).second;
@@ -458,14 +485,37 @@ bool CNode::IsBanned(CNetAddr ip)
return fResult;
}
-bool CNode::Ban(const CNetAddr &addr) {
+void CNode::Ban(const CNetAddr& addr, int64_t bantimeoffset, bool sinceUnixEpoch) {
+ CSubNet subNet(addr.ToString()+(addr.IsIPv4() ? "/32" : "/128"));
+ Ban(subNet, bantimeoffset, sinceUnixEpoch);
+}
+
+void CNode::Ban(const CSubNet& subNet, int64_t bantimeoffset, bool sinceUnixEpoch) {
int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
- {
- LOCK(cs_setBanned);
- if (setBanned[addr] < banTime)
- setBanned[addr] = banTime;
- }
- return true;
+ if (bantimeoffset > 0)
+ banTime = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset;
+
+ LOCK(cs_setBanned);
+ if (setBanned[subNet] < banTime)
+ setBanned[subNet] = banTime;
+}
+
+bool CNode::Unban(const CNetAddr &addr) {
+ CSubNet subNet(addr.ToString()+(addr.IsIPv4() ? "/32" : "/128"));
+ return Unban(subNet);
+}
+
+bool CNode::Unban(const CSubNet &subNet) {
+ LOCK(cs_setBanned);
+ if (setBanned.erase(subNet))
+ return true;
+ return false;
+}
+
+void CNode::GetBanned(std::map<CSubNet, int64_t> &banMap)
+{
+ LOCK(cs_setBanned);
+ banMap = setBanned; //create a thread safe copy
}
@@ -1124,7 +1174,7 @@ void ThreadDNSAddressSeed()
vector<CAddress> vAdd;
if (LookupHost(seed.host.c_str(), vIPs))
{
- BOOST_FOREACH(CNetAddr& ip, vIPs)
+ BOOST_FOREACH(const CNetAddr& ip, vIPs)
{
int nOneDay = 24*3600;
CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()));
@@ -1188,7 +1238,7 @@ void ThreadOpenConnections()
for (int64_t nLoop = 0;; nLoop++)
{
ProcessOneShot();
- BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"])
+ BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-connect"])
{
CAddress addr;
OpenNetworkConnection(addr, NULL, strAddr.c_str());
@@ -1291,10 +1341,10 @@ void ThreadOpenAddedConnections()
list<string> lAddresses(0);
{
LOCK(cs_vAddedNodes);
- BOOST_FOREACH(string& strAddNode, vAddedNodes)
+ BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
lAddresses.push_back(strAddNode);
}
- BOOST_FOREACH(string& strAddNode, lAddresses) {
+ BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
CAddress addr;
CSemaphoreGrant grant(*semOutbound);
OpenNetworkConnection(addr, &grant, strAddNode.c_str());
@@ -1309,20 +1359,19 @@ void ThreadOpenAddedConnections()
list<string> lAddresses(0);
{
LOCK(cs_vAddedNodes);
- BOOST_FOREACH(string& strAddNode, vAddedNodes)
+ BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
lAddresses.push_back(strAddNode);
}
list<vector<CService> > lservAddressesToAdd(0);
- BOOST_FOREACH(string& strAddNode, lAddresses)
- {
+ BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
vector<CService> vservNode(0);
if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0))
{
lservAddressesToAdd.push_back(vservNode);
{
LOCK(cs_setservAddNodeAddresses);
- BOOST_FOREACH(CService& serv, vservNode)
+ BOOST_FOREACH(const CService& serv, vservNode)
setservAddNodeAddresses.insert(serv);
}
}
@@ -1333,7 +1382,7 @@ void ThreadOpenAddedConnections()
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
for (list<vector<CService> >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++)
- BOOST_FOREACH(CService& addrNode, *(it))
+ BOOST_FOREACH(const CService& addrNode, *(it))
if (pnode->addr == addrNode)
{
it = lservAddressesToAdd.erase(it);
@@ -1906,7 +1955,7 @@ bool CAddrDB::Read(CAddrMan& addr)
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) :
+CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) :
ssSend(SER_NETWORK, INIT_PROTO_VERSION),
addrKnown(5000, 0.001, insecure_rand()),
setInventoryKnown(SendBufferSize() / 1000)
diff --git a/src/net.h b/src/net.h
index 17502b97eb..69e4c592a9 100644
--- a/src/net.h
+++ b/src/net.h
@@ -63,9 +63,10 @@ static const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ;
unsigned int ReceiveFloodSize();
unsigned int SendBufferSize();
-void AddOneShot(std::string strDest);
+void AddOneShot(const std::string& strDest);
void AddressCurrentlyConnected(const CService& addr);
CNode* FindNode(const CNetAddr& ip);
+CNode* FindNode(const CSubNet& subNet);
CNode* FindNode(const std::string& addrName);
CNode* FindNode(const CService& ip);
CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL);
@@ -284,7 +285,7 @@ protected:
// Denial-of-service detection/prevention
// Key is IP address, value is banned-until-time
- static std::map<CNetAddr, int64_t> setBanned;
+ static std::map<CSubNet, int64_t> setBanned;
static CCriticalSection cs_setBanned;
// Whitelisted ranges. Any node connecting from these is automatically
@@ -321,7 +322,7 @@ public:
// Whether a ping is requested.
bool fPingQueued;
- CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false);
+ CNode(SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false);
~CNode();
private:
@@ -606,7 +607,13 @@ public:
// new code.
static void ClearBanned(); // needed for unit testing
static bool IsBanned(CNetAddr ip);
- static bool Ban(const CNetAddr &ip);
+ static bool IsBanned(CSubNet subnet);
+ static void Ban(const CNetAddr &ip, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
+ static void Ban(const CSubNet &subNet, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
+ static bool Unban(const CNetAddr &ip);
+ static bool Unban(const CSubNet &ip);
+ static void GetBanned(std::map<CSubNet, int64_t> &banmap);
+
void copyStats(CNodeStats &stats);
static bool IsWhitelistedRange(const CNetAddr &ip);
diff --git a/src/netbase.cpp b/src/netbase.cpp
index e3cb4e706f..adac5c2d07 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -1330,6 +1330,11 @@ bool operator!=(const CSubNet& a, const CSubNet& b)
return !(a==b);
}
+bool operator<(const CSubNet& a, const CSubNet& b)
+{
+ return (a.network < b.network || (a.network == b.network && memcmp(a.netmask, b.netmask, 16) < 0));
+}
+
#ifdef WIN32
std::string NetworkErrorString(int err)
{
diff --git a/src/netbase.h b/src/netbase.h
index 1f2957116e..27f0eac2a2 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -125,6 +125,7 @@ class CSubNet
friend bool operator==(const CSubNet& a, const CSubNet& b);
friend bool operator!=(const CSubNet& a, const CSubNet& b);
+ friend bool operator<(const CSubNet& a, const CSubNet& b);
};
/** A combination of a network address (CNetAddr) and a (TCP) port */
diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui
index c1eb185501..7ae8237476 100644
--- a/src/qt/forms/rpcconsole.ui
+++ b/src/qt/forms/rpcconsole.ui
@@ -745,13 +745,36 @@
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
+ <widget class="QLabel" name="label_30">
+ <property name="text">
+ <string>Whitelisted</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLabel" name="peerWhitelisted">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Direction</string>
</property>
</widget>
</item>
- <item row="0" column="2">
+ <item row="1" column="2">
<widget class="QLabel" name="peerDirection">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -767,14 +790,14 @@
</property>
</widget>
</item>
- <item row="1" column="0">
+ <item row="2" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Version</string>
</property>
</widget>
</item>
- <item row="1" column="2">
+ <item row="2" column="2">
<widget class="QLabel" name="peerVersion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -790,14 +813,14 @@
</property>
</widget>
</item>
- <item row="2" column="0">
+ <item row="3" column="0">
<widget class="QLabel" name="label_28">
<property name="text">
<string>User Agent</string>
</property>
</widget>
</item>
- <item row="2" column="2">
+ <item row="3" column="2">
<widget class="QLabel" name="peerSubversion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -813,14 +836,14 @@
</property>
</widget>
</item>
- <item row="3" column="0">
+ <item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Services</string>
</property>
</widget>
</item>
- <item row="3" column="2">
+ <item row="4" column="2">
<widget class="QLabel" name="peerServices">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -839,7 +862,7 @@
<item row="5" column="0">
<widget class="QLabel" name="label_29">
<property name="text">
- <string>Starting Height</string>
+ <string>Starting Block</string>
</property>
</widget>
</item>
@@ -862,7 +885,7 @@
<item row="6" column="0">
<widget class="QLabel" name="label_27">
<property name="text">
- <string>Sync Height</string>
+ <string>Synced Headers</string>
</property>
</widget>
</item>
@@ -883,13 +906,36 @@
</widget>
</item>
<item row="7" column="0">
+ <widget class="QLabel" name="label_25">
+ <property name="text">
+ <string>Synced Blocks</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="2">
+ <widget class="QLabel" name="peerCommonHeight">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0">
<widget class="QLabel" name="label_24">
<property name="text">
<string>Ban Score</string>
</property>
</widget>
</item>
- <item row="7" column="2">
+ <item row="8" column="2">
<widget class="QLabel" name="peerBanScore">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -905,14 +951,14 @@
</property>
</widget>
</item>
- <item row="8" column="0">
+ <item row="9" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Connection Time</string>
</property>
</widget>
</item>
- <item row="8" column="2">
+ <item row="9" column="2">
<widget class="QLabel" name="peerConnTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -928,14 +974,14 @@
</property>
</widget>
</item>
- <item row="9" column="0">
+ <item row="10" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Last Send</string>
</property>
</widget>
</item>
- <item row="9" column="2">
+ <item row="10" column="2">
<widget class="QLabel" name="peerLastSend">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -951,14 +997,14 @@
</property>
</widget>
</item>
- <item row="10" column="0">
+ <item row="11" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Last Receive</string>
</property>
</widget>
</item>
- <item row="10" column="2">
+ <item row="11" column="2">
<widget class="QLabel" name="peerLastRecv">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -974,14 +1020,14 @@
</property>
</widget>
</item>
- <item row="11" column="0">
+ <item row="12" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Bytes Sent</string>
</property>
</widget>
</item>
- <item row="11" column="2">
+ <item row="12" column="2">
<widget class="QLabel" name="peerBytesSent">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -997,14 +1043,14 @@
</property>
</widget>
</item>
- <item row="12" column="0">
+ <item row="13" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Bytes Received</string>
</property>
</widget>
</item>
- <item row="12" column="2">
+ <item row="13" column="2">
<widget class="QLabel" name="peerBytesRecv">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1020,14 +1066,14 @@
</property>
</widget>
</item>
- <item row="13" column="0">
+ <item row="14" column="0">
<widget class="QLabel" name="label_26">
<property name="text">
<string>Ping Time</string>
</property>
</widget>
</item>
- <item row="13" column="2">
+ <item row="14" column="2">
<widget class="QLabel" name="peerPingTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1043,14 +1089,40 @@
</property>
</widget>
</item>
- <item row="14" column="0">
+ <item row="15" column="0">
+ <widget class="QLabel" name="peerPingWaitLabel">
+ <property name="toolTip">
+ <string>The duration of a currently outstanding ping.</string>
+ </property>
+ <property name="text">
+ <string>Ping Wait</string>
+ </property>
+ </widget>
+ </item>
+ <item row="15" column="2">
+ <widget class="QLabel" name="peerPingWait">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="16" column="0">
<widget class="QLabel" name="label_timeoffset">
<property name="text">
<string>Time Offset</string>
</property>
</widget>
</item>
- <item row="14" column="2">
+ <item row="16" column="2">
<widget class="QLabel" name="timeoffset">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1066,7 +1138,7 @@
</property>
</widget>
</item>
- <item row="15" column="1">
+ <item row="17" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 4a1f728e18..581d2321bc 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -265,6 +265,19 @@ void copyEntryData(QAbstractItemView *view, int column, int role)
}
}
+QString getEntryData(QAbstractItemView *view, int column, int role)
+{
+ if(!view || !view->selectionModel())
+ return QString();
+ QModelIndexList selection = view->selectionModel()->selectedRows(column);
+
+ if(!selection.isEmpty()) {
+ // Return first item
+ return (selection.at(0).data(role).toString());
+ }
+ return QString();
+}
+
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
const QString &filter,
QString *selectedSuffixOut)
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index bcbb540c37..55df64a256 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -64,6 +64,14 @@ namespace GUIUtil
*/
void copyEntryData(QAbstractItemView *view, int column, int role=Qt::EditRole);
+ /** Return a field of the currently selected entry as a QString. Does nothing if nothing
+ is selected.
+ @param[in] column Data column to extract from the model
+ @param[in] role Data role to extract from the model
+ @see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress
+ */
+ QString getEntryData(QAbstractItemView *view, int column, int role);
+
void setClipboard(const QString& str);
/** Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix
@@ -205,7 +213,7 @@ namespace GUIUtil
#else
typedef QProgressBar ProgressBar;
#endif
-
+
} // namespace GUIUtil
#endif // BITCOIN_QT_GUIUTIL_H
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index 220f273d02..f5904a4d8e 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -63,11 +63,12 @@ public:
#if QT_VERSION >= 0x040700
cachedNodeStats.reserve(vNodes.size());
#endif
- BOOST_FOREACH(CNode* pnode, vNodes)
+ foreach (CNode* pnode, vNodes)
{
CNodeCombinedStats stats;
stats.nodeStateStats.nMisbehavior = 0;
stats.nodeStateStats.nSyncHeight = -1;
+ stats.nodeStateStats.nCommonHeight = -1;
stats.fNodeStateStatsAvailable = false;
pnode->copyStats(stats.nodeStats);
cachedNodeStats.append(stats);
@@ -91,7 +92,7 @@ public:
// build index map
mapNodeRows.clear();
int row = 0;
- BOOST_FOREACH(CNodeCombinedStats &stats, cachedNodeStats)
+ foreach (const CNodeCombinedStats& stats, cachedNodeStats)
mapNodeRows.insert(std::pair<NodeId, int>(stats.nodeStats.nodeid, row++));
}
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 29c971ec79..f828ce2534 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -16,15 +16,16 @@
#include "rpcclient.h"
#include "util.h"
-#include "json/json_spirit_value.h"
-
#include <openssl/crypto.h>
+#include "univalue/univalue.h"
+
#ifdef ENABLE_WALLET
#include <db_cxx.h>
#endif
#include <QKeyEvent>
+#include <QMenu>
#include <QScrollBar>
#include <QThread>
#include <QTime>
@@ -167,21 +168,21 @@ void RPCExecutor::request(const QString &command)
std::string strPrint;
// Convert argument list to JSON objects in method-dependent way,
// and pass it along with the method name to the dispatcher.
- json_spirit::Value result = tableRPC.execute(
+ UniValue result = tableRPC.execute(
args[0],
RPCConvertValues(args[0], std::vector<std::string>(args.begin() + 1, args.end())));
// Format result reply
- if (result.type() == json_spirit::null_type)
+ if (result.isNull())
strPrint = "";
- else if (result.type() == json_spirit::str_type)
+ else if (result.isStr())
strPrint = result.get_str();
else
- strPrint = write_string(result, true);
+ strPrint = result.write(2);
emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint));
}
- catch (const json_spirit::Object& objError)
+ catch (UniValue& objError)
{
try // Nice formatting for standard-format error
{
@@ -191,7 +192,7 @@ void RPCExecutor::request(const QString &command)
}
catch (const std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message
{ // Show raw JSON object
- emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(write_string(json_spirit::Value(objError), false)));
+ emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(objError.write()));
}
}
catch (const std::exception& e)
@@ -205,7 +206,8 @@ RPCConsole::RPCConsole(QWidget *parent) :
ui(new Ui::RPCConsole),
clientModel(0),
historyPtr(0),
- cachedNodeid(-1)
+ cachedNodeid(-1),
+ contextMenu(0)
{
ui->setupUi(this);
GUIUtil::restoreWindowGeometry("nRPCConsoleWindow", this->size(), this);
@@ -305,10 +307,22 @@ void RPCConsole::setClientModel(ClientModel *model)
ui->peerWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->peerWidget->setSelectionMode(QAbstractItemView::SingleSelection);
+ ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu);
ui->peerWidget->setColumnWidth(PeerTableModel::Address, ADDRESS_COLUMN_WIDTH);
ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH);
ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH);
+ // create context menu actions
+ QAction* disconnectAction = new QAction(tr("&Disconnect Node"), this);
+
+ // create context menu
+ contextMenu = new QMenu();
+ contextMenu->addAction(disconnectAction);
+
+ // context menu signals
+ connect(ui->peerWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showMenu(const QPoint&)));
+ connect(disconnectAction, SIGNAL(triggered()), this, SLOT(disconnectSelectedNode()));
+
// connect the peerWidget selection model to our peerSelected() handler
connect(ui->peerWidget->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
this, SLOT(peerSelected(const QItemSelection &, const QItemSelection &)));
@@ -471,10 +485,10 @@ void RPCConsole::startExecutor()
void RPCConsole::on_tabWidget_currentChanged(int index)
{
- if(ui->tabWidget->widget(index) == ui->tab_console)
- {
+ if (ui->tabWidget->widget(index) == ui->tab_console)
ui->lineEdit->setFocus();
- }
+ else if (ui->tabWidget->widget(index) != ui->tab_peers)
+ clearSelectedNode();
}
void RPCConsole::on_openDebugLogfileButton_clicked()
@@ -544,12 +558,11 @@ void RPCConsole::peerLayoutChanged()
return;
// find the currently selected row
- int selectedRow;
+ int selectedRow = -1;
QModelIndexList selectedModelIndex = ui->peerWidget->selectionModel()->selectedIndexes();
- if (selectedModelIndex.isEmpty())
- selectedRow = -1;
- else
+ if (!selectedModelIndex.isEmpty()) {
selectedRow = selectedModelIndex.first().row();
+ }
// check if our detail node has a row in the table (it may not necessarily
// be at selectedRow since its position can change after a layout change)
@@ -559,9 +572,6 @@ void RPCConsole::peerLayoutChanged()
{
// detail node dissapeared from table (node disconnected)
fUnselect = true;
- cachedNodeid = -1;
- ui->detailWidget->hide();
- ui->peerHeading->setText(tr("Select a peer to view detailed information."));
}
else
{
@@ -576,10 +586,8 @@ void RPCConsole::peerLayoutChanged()
stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
}
- if (fUnselect && selectedRow >= 0)
- {
- ui->peerWidget->selectionModel()->select(QItemSelection(selectedModelIndex.first(), selectedModelIndex.last()),
- QItemSelectionModel::Deselect);
+ if (fUnselect && selectedRow >= 0) {
+ clearSelectedNode();
}
if (fReselect)
@@ -597,7 +605,8 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
cachedNodeid = stats->nodeStats.nodeid;
// update the detail ui with latest node information
- QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName));
+ QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName) + " ");
+ peerAddrDetails += tr("(node id: %1)").arg(QString::number(stats->nodeStats.nodeid));
if (!stats->nodeStats.addrLocal.empty())
peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal));
ui->peerHeading->setText(peerAddrDetails);
@@ -608,11 +617,13 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
ui->peerBytesRecv->setText(FormatBytes(stats->nodeStats.nRecvBytes));
ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nTimeConnected));
ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingTime));
+ ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingWait));
ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
- ui->peerVersion->setText(QString("%1").arg(stats->nodeStats.nVersion));
+ ui->peerVersion->setText(QString("%1").arg(QString::number(stats->nodeStats.nVersion)));
ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound"));
- ui->peerHeight->setText(QString("%1").arg(stats->nodeStats.nStartingHeight));
+ ui->peerHeight->setText(QString("%1").arg(QString::number(stats->nodeStats.nStartingHeight)));
+ ui->peerWhitelisted->setText(stats->nodeStats.fWhitelisted ? tr("Yes") : tr("No"));
// This check fails for example if the lock was busy and
// nodeStateStats couldn't be fetched.
@@ -625,9 +636,12 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
ui->peerSyncHeight->setText(QString("%1").arg(stats->nodeStateStats.nSyncHeight));
else
ui->peerSyncHeight->setText(tr("Unknown"));
- } else {
- ui->peerBanScore->setText(tr("Fetching..."));
- ui->peerSyncHeight->setText(tr("Fetching..."));
+
+ // Common height is init to -1
+ if (stats->nodeStateStats.nCommonHeight > -1)
+ ui->peerCommonHeight->setText(QString("%1").arg(stats->nodeStateStats.nCommonHeight));
+ else
+ ui->peerCommonHeight->setText(tr("Unknown"));
}
ui->detailWidget->show();
@@ -659,3 +673,29 @@ void RPCConsole::hideEvent(QHideEvent *event)
// stop PeerTableModel auto refresh
clientModel->getPeerTableModel()->stopAutoRefresh();
}
+
+void RPCConsole::showMenu(const QPoint& point)
+{
+ QModelIndex index = ui->peerWidget->indexAt(point);
+ if (index.isValid())
+ contextMenu->exec(QCursor::pos());
+}
+
+void RPCConsole::disconnectSelectedNode()
+{
+ // Get currently selected peer address
+ QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address);
+ // Find the node, disconnect it and clear the selected node
+ if (CNode *bannedNode = FindNode(strNode.toStdString())) {
+ bannedNode->fDisconnect = true;
+ clearSelectedNode();
+ }
+}
+
+void RPCConsole::clearSelectedNode()
+{
+ ui->peerWidget->selectionModel()->clearSelection();
+ cachedNodeid = -1;
+ ui->detailWidget->hide();
+ ui->peerHeading->setText(tr("Select a peer to view detailed information."));
+}
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 8737be35d1..a309df7ba7 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -19,6 +19,7 @@ namespace Ui {
}
QT_BEGIN_NAMESPACE
+class QMenu;
class QItemSelection;
QT_END_NAMESPACE
@@ -57,6 +58,8 @@ private slots:
void resizeEvent(QResizeEvent *event);
void showEvent(QShowEvent *event);
void hideEvent(QHideEvent *event);
+ /** Show custom context menu on Peers tab */
+ void showMenu(const QPoint& point);
public slots:
void clear();
@@ -73,6 +76,8 @@ public slots:
void peerSelected(const QItemSelection &selected, const QItemSelection &deselected);
/** Handle updated peer information */
void peerLayoutChanged();
+ /** Disconnect a selected node on the Peers tab */
+ void disconnectSelectedNode();
signals:
// For RPC command executor
@@ -85,6 +90,8 @@ private:
void setTrafficGraphRange(int mins);
/** show detailed information on ui about selected node */
void updateNodeDetail(const CNodeCombinedStats *stats);
+ /** clear the selected node */
+ void clearSelectedNode();
enum ColumnWidths
{
@@ -98,6 +105,7 @@ private:
QStringList history;
int historyPtr;
NodeId cachedNodeid;
+ QMenu *contextMenu;
};
#endif // BITCOIN_QT_RPCCONSOLE_H
diff --git a/src/rest.cpp b/src/rest.cpp
index 7c238d506d..1fce7dfc9c 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -16,8 +16,9 @@
#include <boost/algorithm/string.hpp>
#include <boost/dynamic_bitset.hpp>
+#include "univalue/univalue.h"
+
using namespace std;
-using namespace json_spirit;
static const int MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once
@@ -61,9 +62,9 @@ public:
string message;
};
-extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry);
-extern Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false);
-extern void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex);
+extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
+extern UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false);
+extern void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
static RestErr RESTERR(enum HTTPStatusCode status, string message)
{
@@ -221,8 +222,8 @@ static bool rest_block(AcceptedConnection* conn,
}
case RF_JSON: {
- Object objBlock = blockToJSON(block, pblockindex, showTxDetails);
- string strJSON = write_string(Value(objBlock), false) + "\n";
+ UniValue objBlock = blockToJSON(block, pblockindex, showTxDetails);
+ string strJSON = objBlock.write() + "\n";
conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
return true;
}
@@ -265,10 +266,9 @@ static bool rest_chaininfo(AcceptedConnection* conn,
switch (rf) {
case RF_JSON: {
- Array rpcParams;
- Value chainInfoObject = getblockchaininfo(rpcParams, false);
-
- string strJSON = write_string(chainInfoObject, false) + "\n";
+ UniValue rpcParams(UniValue::VARR);
+ UniValue chainInfoObject = getblockchaininfo(rpcParams, false);
+ string strJSON = chainInfoObject.write() + "\n";
conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
return true;
}
@@ -317,9 +317,9 @@ static bool rest_tx(AcceptedConnection* conn,
}
case RF_JSON: {
- Object objTx;
+ UniValue objTx(UniValue::VOBJ);
TxToJSON(tx, hashBlock, objTx);
- string strJSON = write_string(Value(objTx), false) + "\n";
+ string strJSON = objTx.write() + "\n";
conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
return true;
}
@@ -492,7 +492,7 @@ static bool rest_getutxos(AcceptedConnection* conn,
}
case RF_JSON: {
- Object objGetUTXOResponse;
+ UniValue objGetUTXOResponse(UniValue::VOBJ);
// pack in some essentials
// use more or less the same output as mentioned in Bip64
@@ -500,15 +500,15 @@ static bool rest_getutxos(AcceptedConnection* conn,
objGetUTXOResponse.push_back(Pair("chaintipHash", chainActive.Tip()->GetBlockHash().GetHex()));
objGetUTXOResponse.push_back(Pair("bitmap", bitmapStringRepresentation));
- Array utxos;
+ UniValue utxos(UniValue::VARR);
BOOST_FOREACH (const CCoin& coin, outs) {
- Object utxo;
+ UniValue utxo(UniValue::VOBJ);
utxo.push_back(Pair("txvers", (int32_t)coin.nTxVer));
utxo.push_back(Pair("height", (int32_t)coin.nHeight));
utxo.push_back(Pair("value", ValueFromAmount(coin.out.nValue)));
// include the script in a json output
- Object o;
+ UniValue o(UniValue::VOBJ);
ScriptPubKeyToJSON(coin.out.scriptPubKey, o, true);
utxo.push_back(Pair("scriptPubKey", o));
utxos.push_back(utxo);
@@ -516,7 +516,7 @@ static bool rest_getutxos(AcceptedConnection* conn,
objGetUTXOResponse.push_back(Pair("utxos", utxos));
// return json string
- string strJSON = write_string(Value(objGetUTXOResponse), false) + "\n";
+ string strJSON = objGetUTXOResponse.write() + "\n";
conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
return true;
}
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index 79528db2fe..85229e9857 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -13,13 +13,12 @@
#include <stdint.h>
-#include "json/json_spirit_value.h"
+#include "univalue/univalue.h"
-using namespace json_spirit;
using namespace std;
-extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry);
-void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex);
+extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
+void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
double GetDifficulty(const CBlockIndex* blockindex)
{
@@ -53,9 +52,9 @@ double GetDifficulty(const CBlockIndex* blockindex)
}
-Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
+UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
{
- Object result;
+ UniValue result(UniValue::VOBJ);
result.push_back(Pair("hash", block.GetHash().GetHex()));
int confirmations = -1;
// Only report confirmations if the block is on the main chain
@@ -66,12 +65,12 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDe
result.push_back(Pair("height", blockindex->nHeight));
result.push_back(Pair("version", block.nVersion));
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
- Array txs;
+ UniValue txs(UniValue::VARR);
BOOST_FOREACH(const CTransaction&tx, block.vtx)
{
if(txDetails)
{
- Object objTx;
+ UniValue objTx(UniValue::VOBJ);
TxToJSON(tx, uint256(), objTx);
txs.push_back(objTx);
}
@@ -94,7 +93,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDe
}
-Value getblockcount(const Array& params, bool fHelp)
+UniValue getblockcount(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -111,7 +110,7 @@ Value getblockcount(const Array& params, bool fHelp)
return chainActive.Height();
}
-Value getbestblockhash(const Array& params, bool fHelp)
+UniValue getbestblockhash(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -128,7 +127,7 @@ Value getbestblockhash(const Array& params, bool fHelp)
return chainActive.Tip()->GetBlockHash().GetHex();
}
-Value getdifficulty(const Array& params, bool fHelp)
+UniValue getdifficulty(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -146,7 +145,7 @@ Value getdifficulty(const Array& params, bool fHelp)
}
-Value getrawmempool(const Array& params, bool fHelp)
+UniValue getrawmempool(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
@@ -187,12 +186,12 @@ Value getrawmempool(const Array& params, bool fHelp)
if (fVerbose)
{
LOCK(mempool.cs);
- Object o;
+ UniValue o(UniValue::VOBJ);
BOOST_FOREACH(const PAIRTYPE(uint256, CTxMemPoolEntry)& entry, mempool.mapTx)
{
const uint256& hash = entry.first;
const CTxMemPoolEntry& e = entry.second;
- Object info;
+ UniValue info(UniValue::VOBJ);
info.push_back(Pair("size", (int)e.GetTxSize()));
info.push_back(Pair("fee", ValueFromAmount(e.GetFee())));
info.push_back(Pair("time", e.GetTime()));
@@ -206,7 +205,13 @@ Value getrawmempool(const Array& params, bool fHelp)
if (mempool.exists(txin.prevout.hash))
setDepends.insert(txin.prevout.hash.ToString());
}
- Array depends(setDepends.begin(), setDepends.end());
+
+ UniValue depends(UniValue::VARR);
+ BOOST_FOREACH(const string& dep, setDepends)
+ {
+ depends.push_back(dep);
+ }
+
info.push_back(Pair("depends", depends));
o.push_back(Pair(hash.ToString(), info));
}
@@ -217,7 +222,7 @@ Value getrawmempool(const Array& params, bool fHelp)
vector<uint256> vtxid;
mempool.queryHashes(vtxid);
- Array a;
+ UniValue a(UniValue::VARR);
BOOST_FOREACH(const uint256& hash, vtxid)
a.push_back(hash.ToString());
@@ -225,7 +230,7 @@ Value getrawmempool(const Array& params, bool fHelp)
}
}
-Value getblockhash(const Array& params, bool fHelp)
+UniValue getblockhash(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -250,7 +255,7 @@ Value getblockhash(const Array& params, bool fHelp)
return pblockindex->GetBlockHash().GetHex();
}
-Value getblock(const Array& params, bool fHelp)
+UniValue getblock(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -318,7 +323,7 @@ Value getblock(const Array& params, bool fHelp)
return blockToJSON(block, pblockindex);
}
-Value gettxoutsetinfo(const Array& params, bool fHelp)
+UniValue gettxoutsetinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -340,9 +345,7 @@ Value gettxoutsetinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("gettxoutsetinfo", "")
);
- LOCK(cs_main);
-
- Object ret;
+ UniValue ret(UniValue::VOBJ);
CCoinsStats stats;
FlushStateToDisk();
@@ -358,7 +361,7 @@ Value gettxoutsetinfo(const Array& params, bool fHelp)
return ret;
}
-Value gettxout(const Array& params, bool fHelp)
+UniValue gettxout(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 2 || params.size() > 3)
throw runtime_error(
@@ -398,7 +401,7 @@ Value gettxout(const Array& params, bool fHelp)
LOCK(cs_main);
- Object ret;
+ UniValue ret(UniValue::VOBJ);
std::string strHash = params[0].get_str();
uint256 hash(uint256S(strHash));
@@ -412,14 +415,14 @@ Value gettxout(const Array& params, bool fHelp)
LOCK(mempool.cs);
CCoinsViewMemPool view(pcoinsTip, mempool);
if (!view.GetCoins(hash, coins))
- return Value::null;
+ return NullUniValue;
mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool
} else {
if (!pcoinsTip->GetCoins(hash, coins))
- return Value::null;
+ return NullUniValue;
}
if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull())
- return Value::null;
+ return NullUniValue;
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
CBlockIndex *pindex = it->second;
@@ -429,7 +432,7 @@ Value gettxout(const Array& params, bool fHelp)
else
ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1));
ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue)));
- Object o;
+ UniValue o(UniValue::VOBJ);
ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true);
ret.push_back(Pair("scriptPubKey", o));
ret.push_back(Pair("version", coins.nVersion));
@@ -438,7 +441,7 @@ Value gettxout(const Array& params, bool fHelp)
return ret;
}
-Value verifychain(const Array& params, bool fHelp)
+UniValue verifychain(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 2)
throw runtime_error(
@@ -466,7 +469,7 @@ Value verifychain(const Array& params, bool fHelp)
return CVerifyDB().VerifyDB(pcoinsTip, nCheckLevel, nCheckDepth);
}
-Value getblockchaininfo(const Array& params, bool fHelp)
+UniValue getblockchaininfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -489,7 +492,7 @@ Value getblockchaininfo(const Array& params, bool fHelp)
LOCK(cs_main);
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("chain", Params().NetworkIDString()));
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1));
@@ -524,7 +527,7 @@ struct CompareBlocksByHeight
}
};
-Value getchaintips(const Array& params, bool fHelp)
+UniValue getchaintips(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -576,10 +579,10 @@ Value getchaintips(const Array& params, bool fHelp)
setTips.insert(chainActive.Tip());
/* Construct the output array. */
- Array res;
+ UniValue res(UniValue::VARR);
BOOST_FOREACH(const CBlockIndex* block, setTips)
{
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("height", block->nHeight));
obj.push_back(Pair("hash", block->phashBlock->GetHex()));
@@ -614,7 +617,7 @@ Value getchaintips(const Array& params, bool fHelp)
return res;
}
-Value getmempoolinfo(const Array& params, bool fHelp)
+UniValue getmempoolinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -630,14 +633,14 @@ Value getmempoolinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getmempoolinfo", "")
);
- Object ret;
+ UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("size", (int64_t) mempool.size()));
ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize()));
return ret;
}
-Value invalidateblock(const Array& params, bool fHelp)
+UniValue invalidateblock(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -672,10 +675,10 @@ Value invalidateblock(const Array& params, bool fHelp)
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
}
- return Value::null;
+ return NullUniValue;
}
-Value reconsiderblock(const Array& params, bool fHelp)
+UniValue reconsiderblock(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -711,5 +714,5 @@ Value reconsiderblock(const Array& params, bool fHelp)
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
}
- return Value::null;
+ return NullUniValue;
}
diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp
index 4b576b3707..4c6b47e4a0 100644
--- a/src/rpcclient.cpp
+++ b/src/rpcclient.cpp
@@ -11,8 +11,10 @@
#include <set>
#include <stdint.h>
+#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
+#include "univalue/univalue.h"
+
using namespace std;
-using namespace json_spirit;
class CRPCConvertParam
{
@@ -76,6 +78,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "signrawtransaction", 1 },
{ "signrawtransaction", 2 },
{ "sendrawtransaction", 1 },
+ { "fundrawtransaction", 1 },
{ "gettxout", 1 },
{ "gettxout", 2 },
{ "gettxoutproof", 0 },
@@ -91,6 +94,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "estimatepriority", 0 },
{ "prioritisetransaction", 1 },
{ "prioritisetransaction", 2 },
+ { "setban", 2 },
+ { "setban", 3 },
};
class CRPCConvertTable
@@ -119,25 +124,32 @@ CRPCConvertTable::CRPCConvertTable()
static CRPCConvertTable rpcCvtTable;
+/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
+ * as well as objects and arrays.
+ */
+UniValue ParseNonRFCJSONValue(const std::string& strVal)
+{
+ UniValue jVal;
+ if (!jVal.read(std::string("[")+strVal+std::string("]")) ||
+ !jVal.isArray() || jVal.size()!=1)
+ throw runtime_error(string("Error parsing JSON:")+strVal);
+ return jVal[0];
+}
+
/** Convert strings to command-specific RPC representation */
-Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
+UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
{
- Array params;
+ UniValue params(UniValue::VARR);
for (unsigned int idx = 0; idx < strParams.size(); idx++) {
const std::string& strVal = strParams[idx];
- // insert string value directly
if (!rpcCvtTable.convert(strMethod, idx)) {
+ // insert string value directly
params.push_back(strVal);
- }
-
- // parse string as JSON, insert bool/number/object/etc. value
- else {
- Value jVal;
- if (!read_string(strVal, jVal))
- throw runtime_error(string("Error parsing JSON:")+strVal);
- params.push_back(jVal);
+ } else {
+ // parse string as JSON, insert bool/number/object/etc. value
+ params.push_back(ParseNonRFCJSONValue(strVal));
}
}
diff --git a/src/rpcclient.h b/src/rpcclient.h
index 42fa2d06fe..d68b4ed6ae 100644
--- a/src/rpcclient.h
+++ b/src/rpcclient.h
@@ -6,10 +6,12 @@
#ifndef BITCOIN_RPCCLIENT_H
#define BITCOIN_RPCCLIENT_H
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_writer_template.h"
+#include "univalue/univalue.h"
-json_spirit::Array RPCConvertValues(const std::string& strMethod, const std::vector<std::string>& strParams);
+UniValue RPCConvertValues(const std::string& strMethod, const std::vector<std::string>& strParams);
+/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
+ * as well as objects and arrays.
+ */
+UniValue ParseNonRFCJSONValue(const std::string& strVal);
#endif // BITCOIN_RPCCLIENT_H
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index 528d5406f4..f332814611 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -24,10 +24,8 @@
#include <boost/assign/list_of.hpp>
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_value.h"
+#include "univalue/univalue.h"
-using namespace json_spirit;
using namespace std;
/**
@@ -35,7 +33,7 @@ using namespace std;
* or from the last difficulty change if 'lookup' is nonpositive.
* If 'height' is nonnegative, compute the estimate at the time when a given block was found.
*/
-Value GetNetworkHashPS(int lookup, int height) {
+UniValue GetNetworkHashPS(int lookup, int height) {
CBlockIndex *pb = chainActive.Tip();
if (height >= 0 && height < chainActive.Height())
@@ -72,7 +70,7 @@ Value GetNetworkHashPS(int lookup, int height) {
return (int64_t)(workDiff.getdouble() / timeDiff);
}
-Value getnetworkhashps(const Array& params, bool fHelp)
+UniValue getnetworkhashps(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 2)
throw runtime_error(
@@ -95,7 +93,7 @@ Value getnetworkhashps(const Array& params, bool fHelp)
}
#ifdef ENABLE_WALLET
-Value getgenerate(const Array& params, bool fHelp)
+UniValue getgenerate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -114,7 +112,7 @@ Value getgenerate(const Array& params, bool fHelp)
return GetBoolArg("-gen", false);
}
-Value generate(const Array& params, bool fHelp)
+UniValue generate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 1)
throw runtime_error(
@@ -147,7 +145,7 @@ Value generate(const Array& params, bool fHelp)
nHeightEnd = nHeightStart+nGenerate;
}
unsigned int nExtraNonce = 0;
- Array blockHashes;
+ UniValue blockHashes(UniValue::VARR);
while (nHeight < nHeightEnd)
{
auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
@@ -173,7 +171,7 @@ Value generate(const Array& params, bool fHelp)
}
-Value setgenerate(const Array& params, bool fHelp)
+UniValue setgenerate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -216,12 +214,12 @@ Value setgenerate(const Array& params, bool fHelp)
mapArgs ["-genproclimit"] = itostr(nGenProcLimit);
GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit);
- return Value::null;
+ return NullUniValue;
}
#endif
-Value getmininginfo(const Array& params, bool fHelp)
+UniValue getmininginfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -248,7 +246,7 @@ Value getmininginfo(const Array& params, bool fHelp)
LOCK(cs_main);
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize));
obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx));
@@ -267,7 +265,7 @@ Value getmininginfo(const Array& params, bool fHelp)
// NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
-Value prioritisetransaction(const Array& params, bool fHelp)
+UniValue prioritisetransaction(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 3)
throw runtime_error(
@@ -299,10 +297,10 @@ Value prioritisetransaction(const Array& params, bool fHelp)
// NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller
-static Value BIP22ValidationResult(const CValidationState& state)
+static UniValue BIP22ValidationResult(const CValidationState& state)
{
if (state.IsValid())
- return Value::null;
+ return NullUniValue;
std::string strRejectReason = state.GetRejectReason();
if (state.IsError())
@@ -317,7 +315,7 @@ static Value BIP22ValidationResult(const CValidationState& state)
return "valid?";
}
-Value getblocktemplate(const Array& params, bool fHelp)
+UniValue getblocktemplate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
@@ -382,14 +380,14 @@ Value getblocktemplate(const Array& params, bool fHelp)
LOCK(cs_main);
std::string strMode = "template";
- Value lpval = Value::null;
+ UniValue lpval = NullUniValue;
if (params.size() > 0)
{
- const Object& oparam = params[0].get_obj();
- const Value& modeval = find_value(oparam, "mode");
- if (modeval.type() == str_type)
+ const UniValue& oparam = params[0].get_obj();
+ const UniValue& modeval = find_value(oparam, "mode");
+ if (modeval.isStr())
strMode = modeval.get_str();
- else if (modeval.type() == null_type)
+ else if (modeval.isNull())
{
/* Do nothing */
}
@@ -399,8 +397,8 @@ Value getblocktemplate(const Array& params, bool fHelp)
if (strMode == "proposal")
{
- const Value& dataval = find_value(oparam, "data");
- if (dataval.type() != str_type)
+ const UniValue& dataval = find_value(oparam, "data");
+ if (!dataval.isStr())
throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal");
CBlock block;
@@ -439,14 +437,14 @@ Value getblocktemplate(const Array& params, bool fHelp)
static unsigned int nTransactionsUpdatedLast;
- if (lpval.type() != null_type)
+ if (!lpval.isNull())
{
// Wait to respond until either the best block changes, OR a minute has passed and there are more transactions
uint256 hashWatchedChain;
boost::system_time checktxtime;
unsigned int nTransactionsUpdatedLastLP;
- if (lpval.type() == str_type)
+ if (lpval.isStr())
{
// Format: <hashBestChain><nTransactionsUpdatedLast>
std::string lpstr = lpval.get_str();
@@ -520,26 +518,25 @@ Value getblocktemplate(const Array& params, bool fHelp)
UpdateTime(pblock, Params().GetConsensus(), pindexPrev);
pblock->nNonce = 0;
- static const Array aCaps = boost::assign::list_of("proposal");
+ UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal");
- Array transactions;
+ UniValue transactions(UniValue::VARR);
map<uint256, int64_t> setTxIndex;
int i = 0;
- BOOST_FOREACH (CTransaction& tx, pblock->vtx)
- {
+ BOOST_FOREACH (const CTransaction& tx, pblock->vtx) {
uint256 txHash = tx.GetHash();
setTxIndex[txHash] = i++;
if (tx.IsCoinBase())
continue;
- Object entry;
+ UniValue entry(UniValue::VOBJ);
entry.push_back(Pair("data", EncodeHexTx(tx)));
entry.push_back(Pair("hash", txHash.GetHex()));
- Array deps;
+ UniValue deps(UniValue::VARR);
BOOST_FOREACH (const CTxIn &in, tx.vin)
{
if (setTxIndex.count(in.prevout.hash))
@@ -554,12 +551,12 @@ Value getblocktemplate(const Array& params, bool fHelp)
transactions.push_back(entry);
}
- Object aux;
+ UniValue aux(UniValue::VOBJ);
aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);
- static Array aMutable;
+ static UniValue aMutable(UniValue::VARR);
if (aMutable.empty())
{
aMutable.push_back("time");
@@ -567,7 +564,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
aMutable.push_back("prevblock");
}
- Object result;
+ UniValue result(UniValue::VOBJ);
result.push_back(Pair("capabilities", aCaps));
result.push_back(Pair("version", pblock->nVersion));
result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
@@ -606,7 +603,7 @@ protected:
};
};
-Value submitblock(const Array& params, bool fHelp)
+UniValue submitblock(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -667,7 +664,7 @@ Value submitblock(const Array& params, bool fHelp)
return BIP22ValidationResult(state);
}
-Value estimatefee(const Array& params, bool fHelp)
+UniValue estimatefee(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -686,7 +683,7 @@ Value estimatefee(const Array& params, bool fHelp)
+ HelpExampleCli("estimatefee", "6")
);
- RPCTypeCheck(params, boost::assign::list_of(int_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
int nBlocks = params[0].get_int();
if (nBlocks < 1)
@@ -699,7 +696,7 @@ Value estimatefee(const Array& params, bool fHelp)
return ValueFromAmount(feeRate.GetFeePerK());
}
-Value estimatepriority(const Array& params, bool fHelp)
+UniValue estimatepriority(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -718,7 +715,7 @@ Value estimatepriority(const Array& params, bool fHelp)
+ HelpExampleCli("estimatepriority", "6")
);
- RPCTypeCheck(params, boost::assign::list_of(int_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
int nBlocks = params[0].get_int();
if (nBlocks < 1)
diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp
index f5bef2a077..1d47bc06a5 100644
--- a/src/rpcmisc.cpp
+++ b/src/rpcmisc.cpp
@@ -20,10 +20,9 @@
#include <stdint.h>
#include <boost/assign/list_of.hpp>
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_value.h"
-using namespace json_spirit;
+#include "univalue/univalue.h"
+
using namespace std;
/**
@@ -39,7 +38,7 @@ using namespace std;
*
* Or alternatively, create a specific query method for the information.
**/
-Value getinfo(const Array& params, bool fHelp)
+UniValue getinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -78,7 +77,7 @@ Value getinfo(const Array& params, bool fHelp)
proxyType proxy;
GetProxy(NET_IPV4, proxy);
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("protocolversion", PROTOCOL_VERSION));
#ifdef ENABLE_WALLET
@@ -108,41 +107,34 @@ Value getinfo(const Array& params, bool fHelp)
}
#ifdef ENABLE_WALLET
-class DescribeAddressVisitor : public boost::static_visitor<Object>
+class DescribeAddressVisitor : public boost::static_visitor<UniValue>
{
-private:
- isminetype mine;
-
public:
- DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
+ UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); }
- Object operator()(const CNoDestination &dest) const { return Object(); }
-
- Object operator()(const CKeyID &keyID) const {
- Object obj;
+ UniValue operator()(const CKeyID &keyID) const {
+ UniValue obj(UniValue::VOBJ);
CPubKey vchPubKey;
obj.push_back(Pair("isscript", false));
- if (mine == ISMINE_SPENDABLE) {
- pwalletMain->GetPubKey(keyID, vchPubKey);
+ if (pwalletMain->GetPubKey(keyID, vchPubKey)) {
obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
}
return obj;
}
- Object operator()(const CScriptID &scriptID) const {
- Object obj;
+ UniValue operator()(const CScriptID &scriptID) const {
+ UniValue obj(UniValue::VOBJ);
+ CScript subscript;
obj.push_back(Pair("isscript", true));
- if (mine != ISMINE_NO) {
- CScript subscript;
- pwalletMain->GetCScript(scriptID, subscript);
+ if (pwalletMain->GetCScript(scriptID, subscript)) {
std::vector<CTxDestination> addresses;
txnouttype whichType;
int nRequired;
ExtractDestinations(subscript, whichType, addresses, nRequired);
obj.push_back(Pair("script", GetTxnOutputType(whichType)));
obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
- Array a;
+ UniValue a(UniValue::VARR);
BOOST_FOREACH(const CTxDestination& addr, addresses)
a.push_back(CBitcoinAddress(addr).ToString());
obj.push_back(Pair("addresses", a));
@@ -154,7 +146,7 @@ public:
};
#endif
-Value validateaddress(const Array& params, bool fHelp)
+UniValue validateaddress(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -187,7 +179,7 @@ Value validateaddress(const Array& params, bool fHelp)
CBitcoinAddress address(params[0].get_str());
bool isValid = address.IsValid();
- Object ret;
+ UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("isvalid", isValid));
if (isValid)
{
@@ -201,11 +193,9 @@ Value validateaddress(const Array& params, bool fHelp)
#ifdef ENABLE_WALLET
isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO;
ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false));
- if (mine != ISMINE_NO) {
- ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false));
- Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
- ret.insert(ret.end(), detail.begin(), detail.end());
- }
+ ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false));
+ UniValue detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
+ ret.pushKVs(detail);
if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
#endif
@@ -216,10 +206,10 @@ Value validateaddress(const Array& params, bool fHelp)
/**
* Used by addmultisigaddress / createmultisig:
*/
-CScript _createmultisig_redeemScript(const Array& params)
+CScript _createmultisig_redeemScript(const UniValue& params)
{
int nRequired = params[0].get_int();
- const Array& keys = params[1].get_array();
+ const UniValue& keys = params[1].get_array();
// Gather public keys
if (nRequired < 1)
@@ -277,7 +267,7 @@ CScript _createmultisig_redeemScript(const Array& params)
return result;
}
-Value createmultisig(const Array& params, bool fHelp)
+UniValue createmultisig(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 2 || params.size() > 2)
{
@@ -313,14 +303,14 @@ Value createmultisig(const Array& params, bool fHelp)
CScriptID innerID(inner);
CBitcoinAddress address(innerID);
- Object result;
+ UniValue result(UniValue::VOBJ);
result.push_back(Pair("address", address.ToString()));
result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
return result;
}
-Value verifymessage(const Array& params, bool fHelp)
+UniValue verifymessage(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 3)
throw runtime_error(
@@ -374,7 +364,7 @@ Value verifymessage(const Array& params, bool fHelp)
return (pubkey.GetID() == keyID);
}
-Value setmocktime(const Array& params, bool fHelp)
+UniValue setmocktime(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -390,8 +380,8 @@ Value setmocktime(const Array& params, bool fHelp)
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(int_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
SetMockTime(params[0].get_int64());
- return Value::null;
+ return NullUniValue;
}
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index bdee5b9f2e..1572b16687 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -16,12 +16,11 @@
#include <boost/foreach.hpp>
-#include "json/json_spirit_value.h"
+#include "univalue/univalue.h"
-using namespace json_spirit;
using namespace std;
-Value getconnectioncount(const Array& params, bool fHelp)
+UniValue getconnectioncount(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -39,7 +38,7 @@ Value getconnectioncount(const Array& params, bool fHelp)
return (int)vNodes.size();
}
-Value ping(const Array& params, bool fHelp)
+UniValue ping(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -59,7 +58,7 @@ Value ping(const Array& params, bool fHelp)
pNode->fPingQueued = true;
}
- return Value::null;
+ return NullUniValue;
}
static void CopyNodeStats(std::vector<CNodeStats>& vstats)
@@ -75,7 +74,7 @@ static void CopyNodeStats(std::vector<CNodeStats>& vstats)
}
}
-Value getpeerinfo(const Array& params, bool fHelp)
+UniValue getpeerinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -120,10 +119,10 @@ Value getpeerinfo(const Array& params, bool fHelp)
vector<CNodeStats> vstats;
CopyNodeStats(vstats);
- Array ret;
+ UniValue ret(UniValue::VARR);
BOOST_FOREACH(const CNodeStats& stats, vstats) {
- Object obj;
+ UniValue obj(UniValue::VOBJ);
CNodeStateStats statestats;
bool fStateStats = GetNodeStateStats(stats.nodeid, statestats);
obj.push_back(Pair("id", stats.nodeid));
@@ -151,7 +150,7 @@ Value getpeerinfo(const Array& params, bool fHelp)
obj.push_back(Pair("banscore", statestats.nMisbehavior));
obj.push_back(Pair("synced_headers", statestats.nSyncHeight));
obj.push_back(Pair("synced_blocks", statestats.nCommonHeight));
- Array heights;
+ UniValue heights(UniValue::VARR);
BOOST_FOREACH(int height, statestats.vHeightInFlight) {
heights.push_back(height);
}
@@ -165,7 +164,7 @@ Value getpeerinfo(const Array& params, bool fHelp)
return ret;
}
-Value addnode(const Array& params, bool fHelp)
+UniValue addnode(const UniValue& params, bool fHelp)
{
string strCommand;
if (params.size() == 2)
@@ -190,7 +189,7 @@ Value addnode(const Array& params, bool fHelp)
{
CAddress addr;
OpenNetworkConnection(addr, NULL, strNode.c_str());
- return Value::null;
+ return NullUniValue;
}
LOCK(cs_vAddedNodes);
@@ -212,10 +211,32 @@ Value addnode(const Array& params, bool fHelp)
vAddedNodes.erase(it);
}
- return Value::null;
+ return NullUniValue;
}
-Value getaddednodeinfo(const Array& params, bool fHelp)
+UniValue disconnectnode(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "disconnectnode \"node\" \n"
+ "\nImmediately disconnects from the specified node.\n"
+ "\nArguments:\n"
+ "1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n"
+ "\nExamples:\n"
+ + HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"")
+ + HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"")
+ );
+
+ CNode* pNode = FindNode(params[0].get_str());
+ if (pNode == NULL)
+ throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
+
+ pNode->fDisconnect = true;
+
+ return NullUniValue;
+}
+
+UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -254,29 +275,29 @@ Value getaddednodeinfo(const Array& params, bool fHelp)
if (params.size() == 1)
{
LOCK(cs_vAddedNodes);
- BOOST_FOREACH(string& strAddNode, vAddedNodes)
+ BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
laddedNodes.push_back(strAddNode);
}
else
{
string strNode = params[1].get_str();
LOCK(cs_vAddedNodes);
- BOOST_FOREACH(string& strAddNode, vAddedNodes)
+ BOOST_FOREACH(const std::string& strAddNode, vAddedNodes) {
if (strAddNode == strNode)
{
laddedNodes.push_back(strAddNode);
break;
}
+ }
if (laddedNodes.size() == 0)
throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
}
- Array ret;
+ UniValue ret(UniValue::VARR);
if (!fDns)
{
- BOOST_FOREACH(string& strAddNode, laddedNodes)
- {
- Object obj;
+ BOOST_FOREACH (const std::string& strAddNode, laddedNodes) {
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("addednode", strAddNode));
ret.push_back(obj);
}
@@ -284,17 +305,16 @@ Value getaddednodeinfo(const Array& params, bool fHelp)
}
list<pair<string, vector<CService> > > laddedAddreses(0);
- BOOST_FOREACH(string& strAddNode, laddedNodes)
- {
+ BOOST_FOREACH(const std::string& strAddNode, laddedNodes) {
vector<CService> vservNode(0);
if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0))
laddedAddreses.push_back(make_pair(strAddNode, vservNode));
else
{
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("addednode", strAddNode));
obj.push_back(Pair("connected", false));
- Array addresses;
+ UniValue addresses(UniValue::VARR);
obj.push_back(Pair("addresses", addresses));
}
}
@@ -302,17 +322,16 @@ Value getaddednodeinfo(const Array& params, bool fHelp)
LOCK(cs_vNodes);
for (list<pair<string, vector<CService> > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++)
{
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("addednode", it->first));
- Array addresses;
+ UniValue addresses(UniValue::VARR);
bool fConnected = false;
- BOOST_FOREACH(CService& addrNode, it->second)
- {
+ BOOST_FOREACH(const CService& addrNode, it->second) {
bool fFound = false;
- Object node;
+ UniValue node(UniValue::VOBJ);
node.push_back(Pair("address", addrNode.ToString()));
- BOOST_FOREACH(CNode* pnode, vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes) {
if (pnode->addr == addrNode)
{
fFound = true;
@@ -320,6 +339,7 @@ Value getaddednodeinfo(const Array& params, bool fHelp)
node.push_back(Pair("connected", pnode->fInbound ? "inbound" : "outbound"));
break;
}
+ }
if (!fFound)
node.push_back(Pair("connected", "false"));
addresses.push_back(node);
@@ -332,7 +352,7 @@ Value getaddednodeinfo(const Array& params, bool fHelp)
return ret;
}
-Value getnettotals(const Array& params, bool fHelp)
+UniValue getnettotals(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 0)
throw runtime_error(
@@ -350,23 +370,23 @@ Value getnettotals(const Array& params, bool fHelp)
+ HelpExampleRpc("getnettotals", "")
);
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv()));
obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent()));
obj.push_back(Pair("timemillis", GetTimeMillis()));
return obj;
}
-static Array GetNetworksInfo()
+static UniValue GetNetworksInfo()
{
- Array networks;
+ UniValue networks(UniValue::VARR);
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;
+ UniValue obj(UniValue::VOBJ);
GetProxy(network, proxy);
obj.push_back(Pair("name", GetNetworkName(network)));
obj.push_back(Pair("limited", IsLimited(network)));
@@ -378,7 +398,7 @@ static Array GetNetworksInfo()
return networks;
}
-Value getnetworkinfo(const Array& params, bool fHelp)
+UniValue getnetworkinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -410,6 +430,7 @@ Value getnetworkinfo(const Array& params, bool fHelp)
" }\n"
" ,...\n"
" ]\n"
+ " \"warnings\": \"...\" (string) any network warnings (such as alert messages) \n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getnetworkinfo", "")
@@ -418,7 +439,7 @@ Value getnetworkinfo(const Array& params, bool fHelp)
LOCK(cs_main);
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("subversion",
FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>())));
@@ -428,12 +449,12 @@ Value getnetworkinfo(const Array& params, bool fHelp)
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("networks", GetNetworksInfo()));
obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
- Array localAddresses;
+ UniValue localAddresses(UniValue::VARR);
{
LOCK(cs_mapLocalHost);
BOOST_FOREACH(const PAIRTYPE(CNetAddr, LocalServiceInfo) &item, mapLocalHost)
{
- Object rec;
+ UniValue rec(UniValue::VOBJ);
rec.push_back(Pair("address", item.first.ToString()));
rec.push_back(Pair("port", item.second.nPort));
rec.push_back(Pair("score", item.second.nScore));
@@ -441,5 +462,112 @@ Value getnetworkinfo(const Array& params, bool fHelp)
}
}
obj.push_back(Pair("localaddresses", localAddresses));
+ obj.push_back(Pair("warnings", GetWarnings("statusbar")));
return obj;
}
+
+UniValue setban(const UniValue& params, bool fHelp)
+{
+ string strCommand;
+ if (params.size() >= 2)
+ strCommand = params[1].get_str();
+ if (fHelp || params.size() < 2 ||
+ (strCommand != "add" && strCommand != "remove"))
+ throw runtime_error(
+ "setban \"ip(/netmask)\" \"add|remove\" (bantime) (absolute)\n"
+ "\nAttempts add or remove a IP/Subnet from the banned list.\n"
+ "\nArguments:\n"
+ "1. \"ip(/netmask)\" (string, required) The IP/Subnet (see getpeerinfo for nodes ip) with a optional netmask (default is /32 = single ip)\n"
+ "2. \"command\" (string, required) 'add' to add a IP/Subnet to the list, 'remove' to remove a IP/Subnet from the list\n"
+ "3. \"bantime\" (numeric, optional) time in seconds how long (or until when if [absolute] is set) the ip is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)\n"
+ "4. \"absolute\" (boolean, optional) If set, the bantime must be a absolute timestamp in seconds since epoch (Jan 1 1970 GMT)\n"
+ "\nExamples:\n"
+ + HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400")
+ + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
+ + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\" 86400")
+ );
+
+ CSubNet subNet;
+ CNetAddr netAddr;
+ bool isSubnet = false;
+
+ if (params[0].get_str().find("/") != string::npos)
+ isSubnet = true;
+
+ if (!isSubnet)
+ netAddr = CNetAddr(params[0].get_str());
+ else
+ subNet = CSubNet(params[0].get_str());
+
+ if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) )
+ throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Invalid IP/Subnet");
+
+ if (strCommand == "add")
+ {
+ if (isSubnet ? CNode::IsBanned(subNet) : CNode::IsBanned(netAddr))
+ throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
+
+ int64_t banTime = 0; //use standard bantime if not specified
+ if (params.size() >= 3 && !params[2].isNull())
+ banTime = params[2].get_int64();
+
+ bool absolute = false;
+ if (params.size() == 4 && params[3].isTrue())
+ absolute = true;
+
+ isSubnet ? CNode::Ban(subNet, banTime, absolute) : CNode::Ban(netAddr, banTime, absolute);
+
+ //disconnect possible nodes
+ while(CNode *bannedNode = (isSubnet ? FindNode(subNet) : FindNode(netAddr)))
+ bannedNode->fDisconnect = true;
+ }
+ else if(strCommand == "remove")
+ {
+ if (!( isSubnet ? CNode::Unban(subNet) : CNode::Unban(netAddr) ))
+ throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed");
+ }
+
+ return NullUniValue;
+}
+
+UniValue listbanned(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "listbanned\n"
+ "\nList all banned IPs/Subnets.\n"
+ "\nExamples:\n"
+ + HelpExampleCli("listbanned", "")
+ + HelpExampleRpc("listbanned", "")
+ );
+
+ std::map<CSubNet, int64_t> banMap;
+ CNode::GetBanned(banMap);
+
+ UniValue bannedAddresses(UniValue::VARR);
+ for (std::map<CSubNet, int64_t>::iterator it = banMap.begin(); it != banMap.end(); it++)
+ {
+ UniValue rec(UniValue::VOBJ);
+ rec.push_back(Pair("address", (*it).first.ToString()));
+ rec.push_back(Pair("banned_untill", (*it).second));
+ bannedAddresses.push_back(rec);
+ }
+
+ return bannedAddresses;
+}
+
+UniValue clearbanned(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "clearbanned\n"
+ "\nClear all banned IPs.\n"
+ "\nExamples:\n"
+ + HelpExampleCli("clearbanned", "")
+ + HelpExampleRpc("clearbanned", "")
+ );
+
+ CNode::ClearBanned();
+
+ return NullUniValue;
+}
diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp
index 95d6b9e531..89dec2977e 100644
--- a/src/rpcprotocol.cpp
+++ b/src/rpcprotocol.cpp
@@ -23,10 +23,10 @@
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/shared_ptr.hpp>
-#include "json/json_spirit_writer_template.h"
+
+#include "univalue/univalue.h"
using namespace std;
-using namespace json_spirit;
//! Number of bytes to allocate and read at most at once in post data
const size_t POST_READ_SIZE = 256 * 1024;
@@ -251,23 +251,22 @@ int ReadHTTPMessage(std::basic_istream<char>& stream, map<string,
*
* 1.0 spec: http://json-rpc.org/wiki/specification
* 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
- * http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
*/
-string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
+string JSONRPCRequest(const string& strMethod, const UniValue& params, const UniValue& id)
{
- Object request;
+ UniValue request(UniValue::VOBJ);
request.push_back(Pair("method", strMethod));
request.push_back(Pair("params", params));
request.push_back(Pair("id", id));
- return write_string(Value(request), false) + "\n";
+ return request.write() + "\n";
}
-Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id)
+UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id)
{
- Object reply;
- if (error.type() != null_type)
- reply.push_back(Pair("result", Value::null));
+ UniValue reply(UniValue::VOBJ);
+ if (!error.isNull())
+ reply.push_back(Pair("result", NullUniValue));
else
reply.push_back(Pair("result", result));
reply.push_back(Pair("error", error));
@@ -275,15 +274,15 @@ Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id)
return reply;
}
-string JSONRPCReply(const Value& result, const Value& error, const Value& id)
+string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id)
{
- Object reply = JSONRPCReplyObj(result, error, id);
- return write_string(Value(reply), false) + "\n";
+ UniValue reply = JSONRPCReplyObj(result, error, id);
+ return reply.write() + "\n";
}
-Object JSONRPCError(int code, const string& message)
+UniValue JSONRPCError(int code, const string& message)
{
- Object error;
+ UniValue error(UniValue::VOBJ);
error.push_back(Pair("code", code));
error.push_back(Pair("message", message));
return error;
diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h
index 4f3f70fb37..ccd2439c9f 100644
--- a/src/rpcprotocol.h
+++ b/src/rpcprotocol.h
@@ -15,9 +15,7 @@
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_writer_template.h"
+#include "univalue/univalue.h"
//! HTTP status codes
enum HTTPStatusCode
@@ -65,6 +63,8 @@ enum RPCErrorCode
RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //! Still downloading initial blocks
RPC_CLIENT_NODE_ALREADY_ADDED = -23, //! Node is already added
RPC_CLIENT_NODE_NOT_ADDED = -24, //! Node has not been added before
+ RPC_CLIENT_NODE_NOT_CONNECTED = -29, //! Node to disconnect not found in connected nodes
+ RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //! Invalid IP/Subnet
//! Wallet errors
RPC_WALLET_ERROR = -4, //! Unspecified problem with wallet (key not found etc.)
@@ -160,9 +160,9 @@ int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto);
int ReadHTTPHeaders(std::basic_istream<char>& stream, std::map<std::string, std::string>& mapHeadersRet);
int ReadHTTPMessage(std::basic_istream<char>& stream, std::map<std::string, std::string>& mapHeadersRet,
std::string& strMessageRet, int nProto, size_t max_size);
-std::string JSONRPCRequest(const std::string& strMethod, const json_spirit::Array& params, const json_spirit::Value& id);
-json_spirit::Object JSONRPCReplyObj(const json_spirit::Value& result, const json_spirit::Value& error, const json_spirit::Value& id);
-std::string JSONRPCReply(const json_spirit::Value& result, const json_spirit::Value& error, const json_spirit::Value& id);
-json_spirit::Object JSONRPCError(int code, const std::string& message);
+std::string JSONRPCRequest(const std::string& strMethod, const UniValue& params, const UniValue& id);
+UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id);
+std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);
+UniValue JSONRPCError(int code, const std::string& message);
#endif // BITCOIN_RPCPROTOCOL_H
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 3e37b797e8..20394fc2c1 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -25,13 +25,12 @@
#include <stdint.h>
#include <boost/assign/list_of.hpp>
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_value.h"
-using namespace json_spirit;
+#include "univalue/univalue.h"
+
using namespace std;
-void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex)
+void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex)
{
txnouttype type;
vector<CTxDestination> addresses;
@@ -49,26 +48,26 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeH
out.push_back(Pair("reqSigs", nRequired));
out.push_back(Pair("type", GetTxnOutputType(type)));
- Array a;
+ UniValue a(UniValue::VARR);
BOOST_FOREACH(const CTxDestination& addr, addresses)
a.push_back(CBitcoinAddress(addr).ToString());
out.push_back(Pair("addresses", a));
}
-void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
+void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
{
entry.push_back(Pair("txid", tx.GetHash().GetHex()));
entry.push_back(Pair("version", tx.nVersion));
entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
- Array vin;
+ UniValue vin(UniValue::VARR);
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
- Object in;
+ UniValue in(UniValue::VOBJ);
if (tx.IsCoinBase())
in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
else {
in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
in.push_back(Pair("vout", (int64_t)txin.prevout.n));
- Object o;
+ UniValue o(UniValue::VOBJ);
o.push_back(Pair("asm", txin.scriptSig.ToString()));
o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
in.push_back(Pair("scriptSig", o));
@@ -77,13 +76,13 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
vin.push_back(in);
}
entry.push_back(Pair("vin", vin));
- Array vout;
+ UniValue vout(UniValue::VARR);
for (unsigned int i = 0; i < tx.vout.size(); i++) {
const CTxOut& txout = tx.vout[i];
- Object out;
+ UniValue out(UniValue::VOBJ);
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
out.push_back(Pair("n", (int64_t)i));
- Object o;
+ UniValue o(UniValue::VOBJ);
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
out.push_back(Pair("scriptPubKey", o));
vout.push_back(out);
@@ -106,7 +105,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
}
}
-Value getrawtransaction(const Array& params, bool fHelp)
+UniValue getrawtransaction(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -190,13 +189,13 @@ Value getrawtransaction(const Array& params, bool fHelp)
if (!fVerbose)
return strHex;
- Object result;
+ UniValue result(UniValue::VOBJ);
result.push_back(Pair("hex", strHex));
TxToJSON(tx, hashBlock, result);
return result;
}
-Value gettxoutproof(const Array& params, bool fHelp)
+UniValue gettxoutproof(const UniValue& params, bool fHelp)
{
if (fHelp || (params.size() != 1 && params.size() != 2))
throw runtime_error(
@@ -220,8 +219,9 @@ Value gettxoutproof(const Array& params, bool fHelp)
set<uint256> setTxids;
uint256 oneTxid;
- Array txids = params[0].get_array();
- BOOST_FOREACH(Value& txid, txids) {
+ UniValue txids = params[0].get_array();
+ for (unsigned int idx = 0; idx < txids.size(); idx++) {
+ const UniValue& txid = txids[idx];
if (txid.get_str().length() != 64 || !IsHex(txid.get_str()))
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid txid ")+txid.get_str());
uint256 hash(uint256S(txid.get_str()));
@@ -276,7 +276,7 @@ Value gettxoutproof(const Array& params, bool fHelp)
return strHex;
}
-Value verifytxoutproof(const Array& params, bool fHelp)
+UniValue verifytxoutproof(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -293,7 +293,7 @@ Value verifytxoutproof(const Array& params, bool fHelp)
CMerkleBlock merkleBlock;
ssMB >> merkleBlock;
- Array res;
+ UniValue res(UniValue::VARR);
vector<uint256> vMatch;
if (merkleBlock.txn.ExtractMatches(vMatch) != merkleBlock.header.hashMerkleRoot)
@@ -309,7 +309,7 @@ Value verifytxoutproof(const Array& params, bool fHelp)
return res;
}
-Value createrawtransaction(const Array& params, bool fHelp)
+UniValue createrawtransaction(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 2)
throw runtime_error(
@@ -343,20 +343,21 @@ Value createrawtransaction(const Array& params, bool fHelp)
);
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(array_type)(obj_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ));
- Array inputs = params[0].get_array();
- Object sendTo = params[1].get_obj();
+ UniValue inputs = params[0].get_array();
+ UniValue sendTo = params[1].get_obj();
CMutableTransaction rawTx;
- BOOST_FOREACH(const Value& input, inputs) {
- const Object& o = input.get_obj();
+ for (unsigned int idx = 0; idx < inputs.size(); idx++) {
+ const UniValue& input = inputs[idx];
+ const UniValue& o = input.get_obj();
uint256 txid = ParseHashO(o, "txid");
- const Value& vout_v = find_value(o, "vout");
- if (vout_v.type() != int_type)
+ const UniValue& vout_v = find_value(o, "vout");
+ if (!vout_v.isNum())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
int nOutput = vout_v.get_int();
if (nOutput < 0)
@@ -367,17 +368,18 @@ Value createrawtransaction(const Array& params, bool fHelp)
}
set<CBitcoinAddress> setAddress;
- BOOST_FOREACH(const Pair& s, sendTo) {
- CBitcoinAddress address(s.name_);
+ vector<string> addrList = sendTo.getKeys();
+ BOOST_FOREACH(const string& name_, addrList) {
+ CBitcoinAddress address(name_);
if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_);
if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
+ throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
setAddress.insert(address);
CScript scriptPubKey = GetScriptForDestination(address.Get());
- CAmount nAmount = AmountFromValue(s.value_);
+ CAmount nAmount = AmountFromValue(sendTo[name_]);
CTxOut out(nAmount, scriptPubKey);
rawTx.vout.push_back(out);
@@ -386,7 +388,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
return EncodeHexTx(rawTx);
}
-Value decoderawtransaction(const Array& params, bool fHelp)
+UniValue decoderawtransaction(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -438,20 +440,20 @@ Value decoderawtransaction(const Array& params, bool fHelp)
);
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(str_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
CTransaction tx;
if (!DecodeHexTx(tx, params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
- Object result;
+ UniValue result(UniValue::VOBJ);
TxToJSON(tx, uint256(), result);
return result;
}
-Value decodescript(const Array& params, bool fHelp)
+UniValue decodescript(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -477,9 +479,9 @@ Value decodescript(const Array& params, bool fHelp)
);
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(str_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
- Object r;
+ UniValue r(UniValue::VOBJ);
CScript script;
if (params[0].get_str().size() > 0){
vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
@@ -494,9 +496,9 @@ Value decodescript(const Array& params, bool fHelp)
}
/** Pushes a JSON object for script verification or signing errors to vErrorsRet. */
-static void TxInErrorToJSON(const CTxIn& txin, Array& vErrorsRet, const std::string& strMessage)
+static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::string& strMessage)
{
- Object entry;
+ UniValue entry(UniValue::VOBJ);
entry.push_back(Pair("txid", txin.prevout.hash.ToString()));
entry.push_back(Pair("vout", (uint64_t)txin.prevout.n));
entry.push_back(Pair("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
@@ -505,7 +507,7 @@ static void TxInErrorToJSON(const CTxIn& txin, Array& vErrorsRet, const std::str
vErrorsRet.push_back(entry);
}
-Value signrawtransaction(const Array& params, bool fHelp)
+UniValue signrawtransaction(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 4)
throw runtime_error(
@@ -570,7 +572,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
#else
LOCK(cs_main);
#endif
- RPCTypeCheck(params, boost::assign::list_of(str_type)(array_type)(array_type)(str_type), true);
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true);
vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
@@ -613,10 +615,11 @@ Value signrawtransaction(const Array& params, bool fHelp)
bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
- if (params.size() > 2 && params[2].type() != null_type) {
+ if (params.size() > 2 && !params[2].isNull()) {
fGivenKeys = true;
- Array keys = params[2].get_array();
- BOOST_FOREACH(Value k, keys) {
+ UniValue keys = params[2].get_array();
+ for (unsigned int idx = 0; idx < keys.size(); idx++) {
+ UniValue k = keys[idx];
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(k.get_str());
if (!fGood)
@@ -633,15 +636,16 @@ Value signrawtransaction(const Array& params, bool fHelp)
#endif
// Add previous txouts given in the RPC call:
- if (params.size() > 1 && params[1].type() != null_type) {
- Array prevTxs = params[1].get_array();
- BOOST_FOREACH(Value& p, prevTxs) {
- if (p.type() != obj_type)
+ if (params.size() > 1 && !params[1].isNull()) {
+ UniValue prevTxs = params[1].get_array();
+ for (unsigned int idx = 0; idx < prevTxs.size(); idx++) {
+ const UniValue& p = prevTxs[idx];
+ if (!p.isObject())
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
- Object prevOut = p.get_obj();
+ UniValue prevOut = p.get_obj();
- RPCTypeCheck(prevOut, boost::assign::map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
+ RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR));
uint256 txid = ParseHashO(prevOut, "txid");
@@ -669,9 +673,9 @@ Value signrawtransaction(const Array& params, bool fHelp)
// if redeemScript given and not using the local wallet (private keys
// given), add redeemScript to the tempKeystore so it can be signed:
if (fGivenKeys && scriptPubKey.IsPayToScriptHash()) {
- RPCTypeCheck(prevOut, boost::assign::map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
- Value v = find_value(prevOut, "redeemScript");
- if (!(v == Value::null)) {
+ RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR)("redeemScript",UniValue::VSTR));
+ UniValue v = find_value(prevOut, "redeemScript");
+ if (!v.isNull()) {
vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
CScript redeemScript(rsData.begin(), rsData.end());
tempKeystore.AddCScript(redeemScript);
@@ -687,7 +691,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
#endif
int nHashType = SIGHASH_ALL;
- if (params.size() > 3 && params[3].type() != null_type) {
+ if (params.size() > 3 && !params[3].isNull()) {
static map<string, int> mapSigHashValues =
boost::assign::map_list_of
(string("ALL"), int(SIGHASH_ALL))
@@ -707,7 +711,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
// Script verification errors
- Array vErrors;
+ UniValue vErrors(UniValue::VARR);
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
@@ -735,7 +739,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
}
bool fComplete = vErrors.empty();
- Object result;
+ UniValue result(UniValue::VOBJ);
result.push_back(Pair("hex", EncodeHexTx(mergedTx)));
result.push_back(Pair("complete", fComplete));
if (!vErrors.empty()) {
@@ -745,7 +749,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
return result;
}
-Value sendrawtransaction(const Array& params, bool fHelp)
+UniValue sendrawtransaction(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -769,7 +773,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
);
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(str_type)(bool_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL));
// parse hex string from parameter
CTransaction tx;
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index 3f74517a67..2f28971589 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -11,6 +11,7 @@
#include "sync.h"
#include "ui_interface.h"
#include "util.h"
+#include "utilmoneystr.h"
#include "utilstrencodings.h"
#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
@@ -27,10 +28,10 @@
#include <boost/shared_ptr.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/thread.hpp>
-#include "json/json_spirit_writer_template.h"
+
+#include "univalue/univalue.h"
using namespace boost::asio;
-using namespace json_spirit;
using namespace RPCServer;
using namespace std;
@@ -78,71 +79,67 @@ void RPCServer::OnPostCommand(boost::function<void (const CRPCCommand&)> slot)
g_rpcSignals.PostCommand.connect(boost::bind(slot, _1));
}
-void RPCTypeCheck(const Array& params,
- const list<Value_type>& typesExpected,
+void RPCTypeCheck(const UniValue& params,
+ const list<UniValue::VType>& typesExpected,
bool fAllowNull)
{
unsigned int i = 0;
- BOOST_FOREACH(Value_type t, typesExpected)
+ BOOST_FOREACH(UniValue::VType t, typesExpected)
{
if (params.size() <= i)
break;
- const Value& v = params[i];
- if (!((v.type() == t) || (fAllowNull && (v.type() == null_type))))
+ const UniValue& v = params[i];
+ if (!((v.type() == t) || (fAllowNull && (v.isNull()))))
{
string err = strprintf("Expected type %s, got %s",
- Value_type_name[t], Value_type_name[v.type()]);
+ uvTypeName(t), uvTypeName(v.type()));
throw JSONRPCError(RPC_TYPE_ERROR, err);
}
i++;
}
}
-void RPCTypeCheck(const Object& o,
- const map<string, Value_type>& typesExpected,
+void RPCTypeCheckObj(const UniValue& o,
+ const map<string, UniValue::VType>& typesExpected,
bool fAllowNull)
{
- BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected)
+ BOOST_FOREACH(const PAIRTYPE(string, UniValue::VType)& t, typesExpected)
{
- const Value& v = find_value(o, t.first);
- if (!fAllowNull && v.type() == null_type)
+ const UniValue& v = find_value(o, t.first);
+ if (!fAllowNull && v.isNull())
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
- if (!((v.type() == t.second) || (fAllowNull && (v.type() == null_type))))
+ if (!((v.type() == t.second) || (fAllowNull && (v.isNull()))))
{
string err = strprintf("Expected type %s for %s, got %s",
- Value_type_name[t.second], t.first, Value_type_name[v.type()]);
+ uvTypeName(t.second), t.first, uvTypeName(v.type()));
throw JSONRPCError(RPC_TYPE_ERROR, err);
}
}
}
-static inline int64_t roundint64(double d)
+CAmount AmountFromValue(const UniValue& value)
{
- return (int64_t)(d > 0 ? d + 0.5 : d - 0.5);
-}
-
-CAmount AmountFromValue(const Value& value)
-{
- double dAmount = value.get_real();
- if (dAmount <= 0.0 || dAmount > 21000000.0)
- throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
- CAmount nAmount = roundint64(dAmount * COIN);
- if (!MoneyRange(nAmount))
+ if (!value.isReal() && !value.isNum())
+ throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number");
+ CAmount amount;
+ if (!ParseMoney(value.getValStr(), amount))
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
- return nAmount;
+ if (!MoneyRange(amount))
+ throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
+ return amount;
}
-Value ValueFromAmount(const CAmount& amount)
+UniValue ValueFromAmount(const CAmount& amount)
{
- return (double)amount / (double)COIN;
+ return UniValue(UniValue::VREAL, FormatMoney(amount));
}
-uint256 ParseHashV(const Value& v, string strName)
+uint256 ParseHashV(const UniValue& v, string strName)
{
string strHex;
- if (v.type() == str_type)
+ if (v.isStr())
strHex = v.get_str();
if (!IsHex(strHex)) // Note: IsHex("") is false
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
@@ -150,20 +147,20 @@ uint256 ParseHashV(const Value& v, string strName)
result.SetHex(strHex);
return result;
}
-uint256 ParseHashO(const Object& o, string strKey)
+uint256 ParseHashO(const UniValue& o, string strKey)
{
return ParseHashV(find_value(o, strKey), strKey);
}
-vector<unsigned char> ParseHexV(const Value& v, string strName)
+vector<unsigned char> ParseHexV(const UniValue& v, string strName)
{
string strHex;
- if (v.type() == str_type)
+ if (v.isStr())
strHex = v.get_str();
if (!IsHex(strHex))
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
return ParseHex(strHex);
}
-vector<unsigned char> ParseHexO(const Object& o, string strKey)
+vector<unsigned char> ParseHexO(const UniValue& o, string strKey)
{
return ParseHexV(find_value(o, strKey), strKey);
}
@@ -173,7 +170,7 @@ vector<unsigned char> ParseHexO(const Object& o, string strKey)
* Note: This interface may still be subject to change.
*/
-string CRPCTable::help(string strCommand) const
+std::string CRPCTable::help(const std::string& strCommand) const
{
string strRet;
string category;
@@ -195,7 +192,7 @@ string CRPCTable::help(string strCommand) const
continue;
try
{
- Array params;
+ UniValue params;
rpcfn_type pfn = pcmd->actor;
if (setDone.insert(pfn).second)
(*pfn)(params, true);
@@ -228,7 +225,7 @@ string CRPCTable::help(string strCommand) const
return strRet;
}
-Value help(const Array& params, bool fHelp)
+UniValue help(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
@@ -248,7 +245,7 @@ Value help(const Array& params, bool fHelp)
}
-Value stop(const Array& params, bool fHelp)
+UniValue stop(const UniValue& params, bool fHelp)
{
// Accept the deprecated and ignored 'detach' boolean argument
if (fHelp || params.size() > 1)
@@ -276,11 +273,15 @@ static const CRPCCommand vRPCCommands[] =
/* P2P networking */
{ "network", "getnetworkinfo", &getnetworkinfo, true },
{ "network", "addnode", &addnode, true },
+ { "network", "disconnectnode", &disconnectnode, true },
{ "network", "getaddednodeinfo", &getaddednodeinfo, true },
{ "network", "getconnectioncount", &getconnectioncount, true },
{ "network", "getnettotals", &getnettotals, true },
{ "network", "getpeerinfo", &getpeerinfo, true },
{ "network", "ping", &ping, true },
+ { "network", "setban", &setban, true },
+ { "network", "listbanned", &listbanned, true },
+ { "network", "clearbanned", &clearbanned, true },
/* Block chain and UTXO */
{ "blockchain", "getblockchaininfo", &getblockchaininfo, true },
@@ -319,6 +320,9 @@ static const CRPCCommand vRPCCommands[] =
{ "rawtransactions", "getrawtransaction", &getrawtransaction, true },
{ "rawtransactions", "sendrawtransaction", &sendrawtransaction, false },
{ "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */
+#ifdef ENABLE_WALLET
+ { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false },
+#endif
/* Utility functions */
{ "util", "createmultisig", &createmultisig, true },
@@ -391,7 +395,7 @@ CRPCTable::CRPCTable()
}
}
-const CRPCCommand *CRPCTable::operator[](string name) const
+const CRPCCommand *CRPCTable::operator[](const std::string& name) const
{
map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
if (it == mapCommands.end())
@@ -410,14 +414,14 @@ bool HTTPAuthorized(map<string, string>& mapHeaders)
return TimingResistantEqual(strUserPass, strRPCUserColonPass);
}
-void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
+void ErrorReply(std::ostream& stream, const UniValue& objError, const UniValue& id)
{
// Send error reply from json-rpc error object
int nStatus = HTTP_INTERNAL_SERVER_ERROR;
int code = find_value(objError, "code").get_int();
if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST;
else if (code == RPC_METHOD_NOT_FOUND) nStatus = HTTP_NOT_FOUND;
- string strReply = JSONRPCReply(Value::null, objError, id);
+ string strReply = JSONRPCReply(NullUniValue, objError, id);
stream << HTTPReply(nStatus, strReply, false) << std::flush;
}
@@ -824,76 +828,76 @@ void RPCRunLater(const std::string& name, boost::function<void(void)> func, int6
class JSONRequest
{
public:
- Value id;
+ UniValue id;
string strMethod;
- Array params;
+ UniValue params;
- JSONRequest() { id = Value::null; }
- void parse(const Value& valRequest);
+ JSONRequest() { id = NullUniValue; }
+ void parse(const UniValue& valRequest);
};
-void JSONRequest::parse(const Value& valRequest)
+void JSONRequest::parse(const UniValue& valRequest)
{
// Parse request
- if (valRequest.type() != obj_type)
+ if (!valRequest.isObject())
throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
- const Object& request = valRequest.get_obj();
+ const UniValue& request = valRequest.get_obj();
// Parse id now so errors from here on will have the id
id = find_value(request, "id");
// Parse method
- Value valMethod = find_value(request, "method");
- if (valMethod.type() == null_type)
+ UniValue valMethod = find_value(request, "method");
+ if (valMethod.isNull())
throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
- if (valMethod.type() != str_type)
+ if (!valMethod.isStr())
throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
strMethod = valMethod.get_str();
if (strMethod != "getblocktemplate")
LogPrint("rpc", "ThreadRPCServer method=%s\n", SanitizeString(strMethod));
// Parse params
- Value valParams = find_value(request, "params");
- if (valParams.type() == array_type)
+ UniValue valParams = find_value(request, "params");
+ if (valParams.isArray())
params = valParams.get_array();
- else if (valParams.type() == null_type)
- params = Array();
+ else if (valParams.isNull())
+ params = UniValue(UniValue::VARR);
else
throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array");
}
-static Object JSONRPCExecOne(const Value& req)
+static UniValue JSONRPCExecOne(const UniValue& req)
{
- Object rpc_result;
+ UniValue rpc_result(UniValue::VOBJ);
JSONRequest jreq;
try {
jreq.parse(req);
- Value result = tableRPC.execute(jreq.strMethod, jreq.params);
- rpc_result = JSONRPCReplyObj(result, Value::null, jreq.id);
+ UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);
+ rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id);
}
- catch (const Object& objError)
+ catch (const UniValue& objError)
{
- rpc_result = JSONRPCReplyObj(Value::null, objError, jreq.id);
+ rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id);
}
catch (const std::exception& e)
{
- rpc_result = JSONRPCReplyObj(Value::null,
+ rpc_result = JSONRPCReplyObj(NullUniValue,
JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
}
return rpc_result;
}
-static string JSONRPCExecBatch(const Array& vReq)
+static string JSONRPCExecBatch(const UniValue& vReq)
{
- Array ret;
+ UniValue ret(UniValue::VARR);
for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
ret.push_back(JSONRPCExecOne(vReq[reqIdx]));
- return write_string(Value(ret), false) + "\n";
+ return ret.write() + "\n";
}
static bool HTTPReq_JSONRPC(AcceptedConnection *conn,
@@ -924,8 +928,8 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn,
try
{
// Parse request
- Value valRequest;
- if (!read_string(strRequest, valRequest))
+ UniValue valRequest;
+ if (!valRequest.read(strRequest))
throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
// Return immediately if in warmup
@@ -938,23 +942,23 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn,
string strReply;
// singleton request
- if (valRequest.type() == obj_type) {
+ if (valRequest.isObject()) {
jreq.parse(valRequest);
- Value result = tableRPC.execute(jreq.strMethod, jreq.params);
+ UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);
// Send reply
- strReply = JSONRPCReply(result, Value::null, jreq.id);
+ strReply = JSONRPCReply(result, NullUniValue, jreq.id);
// array of requests
- } else if (valRequest.type() == array_type)
+ } else if (valRequest.isArray())
strReply = JSONRPCExecBatch(valRequest.get_array());
else
throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
conn->stream() << HTTPReplyHeader(HTTP_OK, fRun, strReply.size()) << strReply << std::flush;
}
- catch (const Object& objError)
+ catch (const UniValue& objError)
{
ErrorReply(conn->stream(), objError, jreq.id);
return false;
@@ -1004,7 +1008,7 @@ void ServiceConnection(AcceptedConnection *conn)
}
}
-json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_spirit::Array &params) const
+UniValue CRPCTable::execute(const std::string &strMethod, const UniValue &params) const
{
// Find method
const CRPCCommand *pcmd = tableRPC[strMethod];
@@ -1026,11 +1030,13 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s
g_rpcSignals.PostCommand(*pcmd);
}
-std::string HelpExampleCli(string methodname, string args){
+std::string HelpExampleCli(const std::string& methodname, const std::string& args)
+{
return "> bitcoin-cli " + methodname + " " + args + "\n";
}
-std::string HelpExampleRpc(string methodname, string args){
+std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
+{
return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", "
"\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
}
diff --git a/src/rpcserver.h b/src/rpcserver.h
index 30a5b28db7..45af10c2a8 100644
--- a/src/rpcserver.h
+++ b/src/rpcserver.h
@@ -15,9 +15,9 @@
#include <stdint.h>
#include <string>
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_writer_template.h"
+#include <boost/function.hpp>
+
+#include "univalue/univalue.h"
class CRPCCommand;
@@ -55,7 +55,7 @@ void StopRPCThreads();
/** Query whether RPC is running */
bool IsRPCRunning();
-/**
+/**
* Set the RPC warmup status. When this is done, all RPC calls will error out
* immediately with RPC_IN_WARMUP.
*/
@@ -71,14 +71,15 @@ bool RPCIsInWarmup(std::string *statusOut);
* the right number of arguments are passed, just that any passed are the correct type.
* Use like: RPCTypeCheck(params, boost::assign::list_of(str_type)(int_type)(obj_type));
*/
-void RPCTypeCheck(const json_spirit::Array& params,
- const std::list<json_spirit::Value_type>& typesExpected, bool fAllowNull=false);
-/**
- * Check for expected keys/value types in an Object.
- * Use like: RPCTypeCheck(object, boost::assign::map_list_of("name", str_type)("value", int_type));
- */
-void RPCTypeCheck(const json_spirit::Object& o,
- const std::map<std::string, json_spirit::Value_type>& typesExpected, bool fAllowNull=false);
+void RPCTypeCheck(const UniValue& params,
+ const std::list<UniValue::VType>& typesExpected, bool fAllowNull=false);
+
+/*
+ Check for expected keys/value types in an Object.
+ Use like: RPCTypeCheckObj(object, boost::assign::map_list_of("name", str_type)("value", int_type));
+*/
+void RPCTypeCheckObj(const UniValue& o,
+ const std::map<std::string, UniValue::VType>& typesExpected, bool fAllowNull=false);
/**
* Run func nSeconds from now. Uses boost deadline timers.
@@ -89,7 +90,7 @@ void RPCRunLater(const std::string& name, boost::function<void(void)> func, int6
//! Convert boost::asio address to CNetAddr
extern CNetAddr BoostAsioToCNetAddr(boost::asio::ip::address address);
-typedef json_spirit::Value(*rpcfn_type)(const json_spirit::Array& params, bool fHelp);
+typedef UniValue(*rpcfn_type)(const UniValue& params, bool fHelp);
class CRPCCommand
{
@@ -109,17 +110,17 @@ private:
std::map<std::string, const CRPCCommand*> mapCommands;
public:
CRPCTable();
- const CRPCCommand* operator[](std::string name) const;
- std::string help(std::string name) const;
+ const CRPCCommand* operator[](const std::string& name) const;
+ std::string help(const std::string& name) const;
/**
* Execute a method.
* @param method Method to execute
- * @param params Array of arguments (JSON objects)
+ * @param params UniValue Array of arguments (JSON objects)
* @returns Result of the call.
- * @throws an exception (json_spirit::Value) when an error happens.
+ * @throws an exception (UniValue) when an error happens.
*/
- json_spirit::Value execute(const std::string &method, const json_spirit::Array &params) const;
+ UniValue execute(const std::string &method, const UniValue &params) const;
};
extern const CRPCTable tableRPC;
@@ -128,113 +129,118 @@ extern const CRPCTable tableRPC;
* Utilities: convert hex-encoded Values
* (throws error if not hex).
*/
-extern uint256 ParseHashV(const json_spirit::Value& v, std::string strName);
-extern uint256 ParseHashO(const json_spirit::Object& o, std::string strKey);
-extern std::vector<unsigned char> ParseHexV(const json_spirit::Value& v, std::string strName);
-extern std::vector<unsigned char> ParseHexO(const json_spirit::Object& o, std::string strKey);
+extern uint256 ParseHashV(const UniValue& v, std::string strName);
+extern uint256 ParseHashO(const UniValue& o, std::string strKey);
+extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName);
+extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
extern void InitRPCMining();
extern void ShutdownRPCMining();
extern int64_t nWalletUnlockTime;
-extern CAmount AmountFromValue(const json_spirit::Value& value);
-extern json_spirit::Value ValueFromAmount(const CAmount& amount);
+extern CAmount AmountFromValue(const UniValue& value);
+extern UniValue ValueFromAmount(const CAmount& amount);
extern double GetDifficulty(const CBlockIndex* blockindex = NULL);
extern std::string HelpRequiringPassphrase();
-extern std::string HelpExampleCli(std::string methodname, std::string args);
-extern std::string HelpExampleRpc(std::string methodname, std::string args);
+extern std::string HelpExampleCli(const std::string& methodname, const std::string& args);
+extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);
extern void EnsureWalletIsUnlocked();
-extern json_spirit::Value getconnectioncount(const json_spirit::Array& params, bool fHelp); // in rpcnet.cpp
-extern json_spirit::Value getpeerinfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value ping(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value addnode(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getaddednodeinfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getnettotals(const json_spirit::Array& params, bool fHelp);
-
-extern json_spirit::Value dumpprivkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp
-extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value importaddress(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value dumpwallet(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fHelp);
-
-extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp
-extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value generate(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getnetworkhashps(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value prioritisetransaction(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value submitblock(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value estimatefee(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value estimatepriority(const json_spirit::Array& params, bool fHelp);
-
-extern json_spirit::Value getnewaddress(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
-extern json_spirit::Value getaccountaddress(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getrawchangeaddress(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value setaccount(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getaccount(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getaddressesbyaccount(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value sendtoaddress(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value signmessage(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value verifymessage(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getreceivedbyaddress(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getreceivedbyaccount(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getbalance(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getunconfirmedbalance(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value movecmd(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value sendfrom(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value sendmany(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value addmultisigaddress(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value createmultisig(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value listreceivedbyaddress(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value listreceivedbyaccount(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value listtransactions(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value listaddressgroupings(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value listaccounts(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value listsinceblock(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value gettransaction(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value backupwallet(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value keypoolrefill(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value walletpassphrase(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value walletpassphrasechange(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value walletlock(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value encryptwallet(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value validateaddress(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getinfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getwalletinfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getblockchaininfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getnetworkinfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value setmocktime(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value resendwallettransactions(const json_spirit::Array& params, bool fHelp);
-
-extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp
-extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value lockunspent(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value listlockunspent(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value createrawtransaction(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value decoderawtransaction(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value decodescript(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value sendrawtransaction(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value gettxoutproof(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value verifytxoutproof(const json_spirit::Array& params, bool fHelp);
-
-extern json_spirit::Value getblockcount(const json_spirit::Array& params, bool fHelp); // in rpcblockchain.cpp
-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);
-extern json_spirit::Value gettxoutsetinfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value gettxout(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value verifychain(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getchaintips(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value invalidateblock(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value reconsiderblock(const json_spirit::Array& params, bool fHelp);
+extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rpcnet.cpp
+extern UniValue getpeerinfo(const UniValue& params, bool fHelp);
+extern UniValue ping(const UniValue& params, bool fHelp);
+extern UniValue addnode(const UniValue& params, bool fHelp);
+extern UniValue disconnectnode(const UniValue& params, bool fHelp);
+extern UniValue getaddednodeinfo(const UniValue& params, bool fHelp);
+extern UniValue getnettotals(const UniValue& params, bool fHelp);
+extern UniValue setban(const UniValue& params, bool fHelp);
+extern UniValue listbanned(const UniValue& params, bool fHelp);
+extern UniValue clearbanned(const UniValue& params, bool fHelp);
+
+extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
+extern UniValue importprivkey(const UniValue& params, bool fHelp);
+extern UniValue importaddress(const UniValue& params, bool fHelp);
+extern UniValue dumpwallet(const UniValue& params, bool fHelp);
+extern UniValue importwallet(const UniValue& params, bool fHelp);
+
+extern UniValue getgenerate(const UniValue& params, bool fHelp); // in rpcmining.cpp
+extern UniValue setgenerate(const UniValue& params, bool fHelp);
+extern UniValue generate(const UniValue& params, bool fHelp);
+extern UniValue getnetworkhashps(const UniValue& params, bool fHelp);
+extern UniValue getmininginfo(const UniValue& params, bool fHelp);
+extern UniValue prioritisetransaction(const UniValue& params, bool fHelp);
+extern UniValue getblocktemplate(const UniValue& params, bool fHelp);
+extern UniValue submitblock(const UniValue& params, bool fHelp);
+extern UniValue estimatefee(const UniValue& params, bool fHelp);
+extern UniValue estimatepriority(const UniValue& params, bool fHelp);
+
+extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp
+extern UniValue getaccountaddress(const UniValue& params, bool fHelp);
+extern UniValue getrawchangeaddress(const UniValue& params, bool fHelp);
+extern UniValue setaccount(const UniValue& params, bool fHelp);
+extern UniValue getaccount(const UniValue& params, bool fHelp);
+extern UniValue getaddressesbyaccount(const UniValue& params, bool fHelp);
+extern UniValue sendtoaddress(const UniValue& params, bool fHelp);
+extern UniValue signmessage(const UniValue& params, bool fHelp);
+extern UniValue verifymessage(const UniValue& params, bool fHelp);
+extern UniValue getreceivedbyaddress(const UniValue& params, bool fHelp);
+extern UniValue getreceivedbyaccount(const UniValue& params, bool fHelp);
+extern UniValue getbalance(const UniValue& params, bool fHelp);
+extern UniValue getunconfirmedbalance(const UniValue& params, bool fHelp);
+extern UniValue movecmd(const UniValue& params, bool fHelp);
+extern UniValue sendfrom(const UniValue& params, bool fHelp);
+extern UniValue sendmany(const UniValue& params, bool fHelp);
+extern UniValue addmultisigaddress(const UniValue& params, bool fHelp);
+extern UniValue createmultisig(const UniValue& params, bool fHelp);
+extern UniValue listreceivedbyaddress(const UniValue& params, bool fHelp);
+extern UniValue listreceivedbyaccount(const UniValue& params, bool fHelp);
+extern UniValue listtransactions(const UniValue& params, bool fHelp);
+extern UniValue listaddressgroupings(const UniValue& params, bool fHelp);
+extern UniValue listaccounts(const UniValue& params, bool fHelp);
+extern UniValue listsinceblock(const UniValue& params, bool fHelp);
+extern UniValue gettransaction(const UniValue& params, bool fHelp);
+extern UniValue backupwallet(const UniValue& params, bool fHelp);
+extern UniValue keypoolrefill(const UniValue& params, bool fHelp);
+extern UniValue walletpassphrase(const UniValue& params, bool fHelp);
+extern UniValue walletpassphrasechange(const UniValue& params, bool fHelp);
+extern UniValue walletlock(const UniValue& params, bool fHelp);
+extern UniValue encryptwallet(const UniValue& params, bool fHelp);
+extern UniValue validateaddress(const UniValue& params, bool fHelp);
+extern UniValue getinfo(const UniValue& params, bool fHelp);
+extern UniValue getwalletinfo(const UniValue& params, bool fHelp);
+extern UniValue getblockchaininfo(const UniValue& params, bool fHelp);
+extern UniValue getnetworkinfo(const UniValue& params, bool fHelp);
+extern UniValue setmocktime(const UniValue& params, bool fHelp);
+extern UniValue resendwallettransactions(const UniValue& params, bool fHelp);
+
+extern UniValue getrawtransaction(const UniValue& params, bool fHelp); // in rcprawtransaction.cpp
+extern UniValue listunspent(const UniValue& params, bool fHelp);
+extern UniValue lockunspent(const UniValue& params, bool fHelp);
+extern UniValue listlockunspent(const UniValue& params, bool fHelp);
+extern UniValue createrawtransaction(const UniValue& params, bool fHelp);
+extern UniValue decoderawtransaction(const UniValue& params, bool fHelp);
+extern UniValue decodescript(const UniValue& params, bool fHelp);
+extern UniValue fundrawtransaction(const UniValue& params, bool fHelp);
+extern UniValue signrawtransaction(const UniValue& params, bool fHelp);
+extern UniValue sendrawtransaction(const UniValue& params, bool fHelp);
+extern UniValue gettxoutproof(const UniValue& params, bool fHelp);
+extern UniValue verifytxoutproof(const UniValue& params, bool fHelp);
+
+extern UniValue getblockcount(const UniValue& params, bool fHelp); // in rpcblockchain.cpp
+extern UniValue getbestblockhash(const UniValue& params, bool fHelp);
+extern UniValue getdifficulty(const UniValue& params, bool fHelp);
+extern UniValue settxfee(const UniValue& params, bool fHelp);
+extern UniValue getmempoolinfo(const UniValue& params, bool fHelp);
+extern UniValue getrawmempool(const UniValue& params, bool fHelp);
+extern UniValue getblockhash(const UniValue& params, bool fHelp);
+extern UniValue getblock(const UniValue& params, bool fHelp);
+extern UniValue gettxoutsetinfo(const UniValue& params, bool fHelp);
+extern UniValue gettxout(const UniValue& params, bool fHelp);
+extern UniValue verifychain(const UniValue& params, bool fHelp);
+extern UniValue getchaintips(const UniValue& params, bool fHelp);
+extern UniValue invalidateblock(const UniValue& params, bool fHelp);
+extern UniValue reconsiderblock(const UniValue& params, bool fHelp);
// in rest.cpp
extern bool HTTPReq_REST(AcceptedConnection *conn,
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
index c42eb7244d..d5bb588b71 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -50,8 +50,10 @@ void CScheduler::serviceQueue()
// Keep waiting until timeout
}
#else
+ // Some boost versions have a conflicting overload of wait_until that returns void.
+ // Explicitly use a template here to avoid hitting that overload.
while (!shouldStop() && !taskQueue.empty() &&
- newTaskScheduled.wait_until(lock, taskQueue.begin()->first) != boost::cv_status::timeout) {
+ newTaskScheduled.wait_until<>(lock, taskQueue.begin()->first) != boost::cv_status::timeout) {
// Keep waiting until timeout
}
#endif
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index eab629cd91..4543ca303f 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -275,3 +275,39 @@ CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecke
return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2);
}
+
+namespace {
+/** Dummy signature checker which accepts all signatures. */
+class DummySignatureChecker : public BaseSignatureChecker
+{
+public:
+ DummySignatureChecker() {}
+
+ bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
+ {
+ return true;
+ }
+};
+const DummySignatureChecker dummyChecker;
+}
+
+const BaseSignatureChecker& DummySignatureCreator::Checker() const
+{
+ return dummyChecker;
+}
+
+bool DummySignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const
+{
+ // Create a dummy signature that is a valid DER-encoding
+ vchSig.assign(72, '\000');
+ vchSig[0] = 0x30;
+ vchSig[1] = 69;
+ vchSig[2] = 0x02;
+ vchSig[3] = 33;
+ vchSig[4] = 0x01;
+ vchSig[4 + 33] = 0x02;
+ vchSig[5 + 33] = 32;
+ vchSig[6 + 33] = 0x01;
+ vchSig[6 + 33 + 32] = SIGHASH_ALL;
+ return true;
+}
diff --git a/src/script/sign.h b/src/script/sign.h
index 0c4cf61e5e..13f45007dd 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -43,6 +43,14 @@ public:
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const;
};
+/** A signature creator that just produces 72-byte empty signatyres. */
+class DummySignatureCreator : public BaseSignatureCreator {
+public:
+ DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
+ const BaseSignatureChecker& Checker() const;
+ bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const;
+};
+
/** Produce a script signature using a generic signature creator. */
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, CScript& scriptSig);
diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp
index 642ce13bcd..703cf307d1 100644
--- a/src/test/Checkpoints_tests.cpp
+++ b/src/test/Checkpoints_tests.cpp
@@ -21,21 +21,7 @@ BOOST_FIXTURE_TEST_SUITE(Checkpoints_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(sanity)
{
const Checkpoints::CCheckpointData& checkpoints = Params(CBaseChainParams::MAIN).Checkpoints();
- uint256 p11111 = uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d");
- uint256 p134444 = uint256S("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe");
- BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 11111, p11111));
- BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 134444, p134444));
-
-
- // Wrong hashes at checkpoints should fail:
- BOOST_CHECK(!Checkpoints::CheckBlock(checkpoints, 11111, p134444));
- BOOST_CHECK(!Checkpoints::CheckBlock(checkpoints, 134444, p11111));
-
- // ... but any hash not at a checkpoint should succeed:
- BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 11111+1, p134444));
- BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 134444+1, p11111));
-
BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate(checkpoints) >= 134444);
-}
+}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp
index 22cb475e02..38dcc6023c 100644
--- a/src/test/alert_tests.cpp
+++ b/src/test/alert_tests.cpp
@@ -201,7 +201,6 @@ BOOST_AUTO_TEST_CASE(PartitionAlert)
{
// Test PartitionCheck
CCriticalSection csDummy;
- CChain chainDummy;
CBlockIndex indexDummy[100];
CChainParams& params = Params(CBaseChainParams::MAIN);
int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing;
@@ -220,17 +219,16 @@ BOOST_AUTO_TEST_CASE(PartitionAlert)
// Other members don't matter, the partition check code doesn't
// use them
}
- chainDummy.SetTip(&indexDummy[99]);
// Test 1: chain with blocks every nPowTargetSpacing seconds,
// as normal, no worries:
- PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing);
+ PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
BOOST_CHECK(strMiscWarning.empty());
// Test 2: go 3.5 hours without a block, expect a warning:
now += 3*60*60+30*60;
SetMockTime(now);
- PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing);
+ PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
BOOST_CHECK(!strMiscWarning.empty());
BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
strMiscWarning = "";
@@ -239,7 +237,7 @@ BOOST_AUTO_TEST_CASE(PartitionAlert)
// code:
now += 60*10;
SetMockTime(now);
- PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing);
+ PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
BOOST_CHECK(strMiscWarning.empty());
// Test 4: get 2.5 times as many blocks as expected:
@@ -248,7 +246,7 @@ BOOST_AUTO_TEST_CASE(PartitionAlert)
int64_t quickSpacing = nPowTargetSpacing*2/5;
for (int i = 0; i < 100; i++) // Tweak chain timestamps:
indexDummy[i].nTime = now - (100-i)*quickSpacing;
- PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing);
+ PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
BOOST_CHECK(!strMiscWarning.empty());
BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
strMiscWarning = "";
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index f07dd7a7db..9e74f5f427 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -17,23 +17,20 @@
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_writer_template.h"
-using namespace json_spirit;
-extern Array read_json(const std::string& jsondata);
+#include "univalue/univalue.h"
+
+extern UniValue read_json(const std::string& jsondata);
BOOST_FIXTURE_TEST_SUITE(base58_tests, BasicTestingSetup)
// Goal: test low-level base58 encoding functionality
BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
{
- Array tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+ UniValue tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 2) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
@@ -50,13 +47,12 @@ BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
// Goal: test low-level base58 decoding functionality
BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
{
- Array tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
+ UniValue tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
std::vector<unsigned char> result;
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 2) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
@@ -124,16 +120,15 @@ public:
// Goal: check that parsed keys match test payload
BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
{
- Array tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
+ UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
std::vector<unsigned char> result;
CBitcoinSecret secret;
CBitcoinAddress addr;
SelectParams(CBaseChainParams::MAIN);
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 3) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
@@ -141,7 +136,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
}
std::string exp_base58string = test[0].get_str();
std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
- const Object &metadata = test[2].get_obj();
+ const UniValue &metadata = test[2].get_obj();
bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
bool isTestnet = find_value(metadata, "isTestnet").get_bool();
if (isTestnet)
@@ -183,12 +178,12 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
// Goal: check that generated keys match test vectors
BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
{
- Array tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
+ UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
std::vector<unsigned char> result;
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 3) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
@@ -196,7 +191,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
}
std::string exp_base58string = test[0].get_str();
std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
- const Object &metadata = test[2].get_obj();
+ const UniValue &metadata = test[2].get_obj();
bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
bool isTestnet = find_value(metadata, "isTestnet").get_bool();
if (isTestnet)
@@ -251,15 +246,14 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
// Goal: check that base58 parsing code is robust against a variety of corrupted data
BOOST_AUTO_TEST_CASE(base58_keys_invalid)
{
- Array tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
+ UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
std::vector<unsigned char> result;
CBitcoinSecret secret;
CBitcoinAddress addr;
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 1) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 9e4fd8513e..212be0d2d6 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -74,6 +74,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
pblock->nVersion = 1;
pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;
CMutableTransaction txCoinbase(pblock->vtx[0]);
+ txCoinbase.nVersion = 1;
txCoinbase.vin[0].scriptSig = CScript();
txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce);
txCoinbase.vin[0].scriptSig.push_back(chainActive.Height());
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 5899671d2f..c38df0ecf3 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -13,35 +13,36 @@
#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>
+#include "univalue/univalue.h"
+
using namespace std;
-using namespace json_spirit;
-Array
+UniValue
createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL)
{
- Array result;
+ UniValue result(UniValue::VARR);
result.push_back(nRequired);
- Array addresses;
+ UniValue addresses(UniValue::VARR);
if (address1) addresses.push_back(address1);
if (address2) addresses.push_back(address2);
result.push_back(addresses);
return result;
}
-Value CallRPC(string args)
+UniValue CallRPC(string args)
{
vector<string> vArgs;
boost::split(vArgs, args, boost::is_any_of(" \t"));
string strMethod = vArgs[0];
vArgs.erase(vArgs.begin());
- Array params = RPCConvertValues(strMethod, vArgs);
+ UniValue params = RPCConvertValues(strMethod, vArgs);
rpcfn_type method = tableRPC[strMethod]->actor;
try {
- Value result = (*method)(params, false);
+ UniValue result = (*method)(params, false);
return result;
}
- catch (const Object& objError) {
+ catch (const UniValue& objError) {
throw runtime_error(find_value(objError, "message").get_str());
}
}
@@ -52,7 +53,7 @@ BOOST_FIXTURE_TEST_SUITE(rpc_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(rpc_rawparams)
{
// Test raw transaction API argument handling
- Value r;
+ UniValue r;
BOOST_CHECK_THROW(CallRPC("getrawtransaction"), runtime_error);
BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), runtime_error);
@@ -92,7 +93,7 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams)
BOOST_AUTO_TEST_CASE(rpc_rawsign)
{
- Value r;
+ UniValue r;
// input is a 1-of-2 multisig (so is output):
string prevout =
"[{\"txid\":\"b4cc287e58f87cdae59417329f710f3ecd75a4ee1d2872b7248f50977c8493f3\","
@@ -111,25 +112,28 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign)
BOOST_AUTO_TEST_CASE(rpc_format_monetary_values)
{
- 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");
+ BOOST_CHECK(ValueFromAmount(0LL).write() == "0.00000000");
+ BOOST_CHECK(ValueFromAmount(1LL).write() == "0.00000001");
+ BOOST_CHECK(ValueFromAmount(17622195LL).write() == "0.17622195");
+ BOOST_CHECK(ValueFromAmount(50000000LL).write() == "0.50000000");
+ BOOST_CHECK(ValueFromAmount(89898989LL).write() == "0.89898989");
+ BOOST_CHECK(ValueFromAmount(100000000LL).write() == "1.00000000");
+ BOOST_CHECK(ValueFromAmount(2099999999999990LL).write() == "20999999.99999990");
+ BOOST_CHECK(ValueFromAmount(2099999999999999LL).write() == "20999999.99999999");
}
-static Value ValueFromString(const std::string &str)
+static UniValue ValueFromString(const std::string &str)
{
- Value value;
- BOOST_CHECK(read_string(str, value));
+ UniValue value;
+ BOOST_CHECK(value.setNumStr(str));
return value;
}
BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
{
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("-0.00000001")), UniValue);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0")), 0LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000000")), 0LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001")), 1LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.17622195")), 17622195LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.5")), 50000000LL);
@@ -142,20 +146,20 @@ BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
BOOST_AUTO_TEST_CASE(json_parse_errors)
{
- Value value;
// Valid
- BOOST_CHECK_EQUAL(read_string(std::string("1.0"), value), true);
- // Valid, with trailing whitespace
- BOOST_CHECK_EQUAL(read_string(std::string("1.0 "), value), true);
+ BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0").get_real(), 1.0);
+ // Valid, with leading or trailing whitespace
+ BOOST_CHECK_EQUAL(ParseNonRFCJSONValue(" 1.0").get_real(), 1.0);
+ BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0 ").get_real(), 1.0);
// Invalid, initial garbage
- BOOST_CHECK_EQUAL(read_string(std::string("[1.0"), value), false);
- BOOST_CHECK_EQUAL(read_string(std::string("a1.0"), value), false);
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("[1.0"), std::runtime_error);
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("a1.0"), std::runtime_error);
// Invalid, trailing garbage
- BOOST_CHECK_EQUAL(read_string(std::string("1.0sds"), value), false);
- BOOST_CHECK_EQUAL(read_string(std::string("1.0]"), value), false);
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0sds"), std::runtime_error);
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0]"), std::runtime_error);
// BTC addresses should fail parsing
- BOOST_CHECK_EQUAL(read_string(std::string("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"), value), false);
- BOOST_CHECK_EQUAL(read_string(std::string("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL"), value), false);
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"), std::runtime_error);
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL"), std::runtime_error);
}
BOOST_AUTO_TEST_CASE(rpc_boostasiotocnetaddr)
@@ -173,4 +177,87 @@ BOOST_AUTO_TEST_CASE(rpc_boostasiotocnetaddr)
BOOST_CHECK_EQUAL(BoostAsioToCNetAddr(boost::asio::ip::address::from_string("::ffff:127.0.0.1")).ToString(), "127.0.0.1");
}
+BOOST_AUTO_TEST_CASE(rpc_ban)
+{
+ BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
+
+ UniValue r;
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0 add")));
+ BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.0:8334")), runtime_error); //portnumber for setban not allowed
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ UniValue ar = r.get_array();
+ UniValue o1 = ar[0].get_obj();
+ UniValue adr = find_value(o1, "address");
+ BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/255.255.255.255");
+ BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0 remove")));;
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ ar = r.get_array();
+ BOOST_CHECK_EQUAL(ar.size(), 0);
+
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/24 add 1607731200 true")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ ar = r.get_array();
+ o1 = ar[0].get_obj();
+ adr = find_value(o1, "address");
+ UniValue banned_until = find_value(o1, "banned_untill");
+ BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/255.255.255.0");
+ BOOST_CHECK_EQUAL(banned_until.get_int64(), 1607731200); // absolute time check
+
+ BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
+
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/24 add 200")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ ar = r.get_array();
+ o1 = ar[0].get_obj();
+ adr = find_value(o1, "address");
+ banned_until = find_value(o1, "banned_untill");
+ BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/255.255.255.0");
+ int64_t now = GetTime();
+ BOOST_CHECK(banned_until.get_int64() > now);
+ BOOST_CHECK(banned_until.get_int64()-now <= 200);
+
+ // must throw an exception because 127.0.0.1 is in already banned suubnet range
+ BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.1 add")), runtime_error);
+
+ BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0/24 remove")));;
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ ar = r.get_array();
+ BOOST_CHECK_EQUAL(ar.size(), 0);
+
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/255.255.0.0 add")));
+ BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.1.1 add")), runtime_error);
+
+ BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ ar = r.get_array();
+ BOOST_CHECK_EQUAL(ar.size(), 0);
+
+
+ BOOST_CHECK_THROW(r = CallRPC(string("setban test add")), runtime_error); //invalid IP
+
+ //IPv6 tests
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("setban FE80:0000:0000:0000:0202:B3FF:FE1E:8329 add")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ ar = r.get_array();
+ o1 = ar[0].get_obj();
+ adr = find_value(o1, "address");
+ BOOST_CHECK_EQUAL(adr.get_str(), "fe80::202:b3ff:fe1e:8329/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
+
+ BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 2001:db8::/30 add")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ ar = r.get_array();
+ o1 = ar[0].get_obj();
+ adr = find_value(o1, "address");
+ BOOST_CHECK_EQUAL(adr.get_str(), "2001:db8::/ffff:fffc:0:0:0:0:0:0");
+
+ BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128 add")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ ar = r.get_array();
+ o1 = ar[0].get_obj();
+ adr = find_value(o1, "address");
+ BOOST_CHECK_EQUAL(adr.get_str(), "2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp
index 4d5e92cbd4..9368963ff2 100644
--- a/src/test/rpc_wallet_tests.cpp
+++ b/src/test/rpc_wallet_tests.cpp
@@ -14,11 +14,12 @@
#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>
+#include "univalue/univalue.h"
+
using namespace std;
-using namespace json_spirit;
-extern Array createArgs(int nRequired, const char* address1 = NULL, const char* address2 = NULL);
-extern Value CallRPC(string args);
+extern UniValue createArgs(int nRequired, const char* address1 = NULL, const char* address2 = NULL);
+extern UniValue CallRPC(string args);
extern CWallet* pwalletMain;
@@ -35,7 +36,7 @@ BOOST_AUTO_TEST_CASE(rpc_addmultisig)
// new, compressed:
const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4";
- Value v;
+ UniValue v;
CBitcoinAddress address;
BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false));
address.SetString(v.get_str());
@@ -66,13 +67,13 @@ BOOST_AUTO_TEST_CASE(rpc_addmultisig)
BOOST_AUTO_TEST_CASE(rpc_wallet)
{
// Test RPC calls for various wallet statistics
- Value r;
+ UniValue r;
LOCK2(cs_main, pwalletMain->cs_wallet);
CPubKey demoPubkey = pwalletMain->GenerateNewKey();
CBitcoinAddress demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID()));
- Value retValue;
+ UniValue retValue;
string strAccount = "walletDemoAccount";
string strPurpose = "receive";
BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */
@@ -213,9 +214,15 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
*********************************/
BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error);
BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount));
- Array arr = retValue.get_array();
+ UniValue arr = retValue.get_array();
BOOST_CHECK(arr.size() > 0);
BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get());
+
+ /*********************************
+ * fundrawtransaction
+ *********************************/
+ BOOST_CHECK_THROW(CallRPC("fundrawtransaction 28z"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("fundrawtransaction 01000000000180969800000000001976a91450ce0a4b0ee0ddeb633da85199728b940ac3fe9488ac00000000"), runtime_error);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index c0614cca43..3733425699 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -26,12 +26,10 @@
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_writer_template.h"
+
+#include "univalue/univalue.h"
using namespace std;
-using namespace json_spirit;
// Uncomment if you want to output updated JSON tests.
// #define UPDATE_JSON_TESTS
@@ -41,15 +39,15 @@ static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
unsigned int ParseScriptFlags(string strFlags);
string FormatScriptFlags(unsigned int flags);
-Array
+UniValue
read_json(const std::string& jsondata)
{
- Value v;
+ UniValue v;
- if (!read_string(jsondata, v) || v.type() != array_type)
+ if (!v.read(jsondata) || !v.isArray())
{
BOOST_ERROR("Parse error.");
- return Array();
+ return UniValue(UniValue::VARR);
}
return v.get_array();
}
@@ -295,10 +293,10 @@ public:
return *this;
}
- Array GetJSON()
+ UniValue GetJSON()
{
DoPush();
- Array array;
+ UniValue array(UniValue::VARR);
array.push_back(FormatScript(spendTx.vin[0].scriptSig));
array.push_back(FormatScript(creditTx.vout[0].scriptPubKey));
array.push_back(FormatScriptFlags(flags));
@@ -582,14 +580,16 @@ BOOST_AUTO_TEST_CASE(script_build)
std::set<std::string> tests_bad;
{
- Array json_good = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
- Array json_bad = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
+ UniValue json_good = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
+ UniValue json_bad = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
- BOOST_FOREACH(Value& tv, json_good) {
- tests_good.insert(write_string(Value(tv.get_array()), true));
+ for (unsigned int idx = 0; idx < json_good.size(); idx++) {
+ const UniValue& tv = json_good[idx];
+ tests_good.insert(tv.get_array().write());
}
- BOOST_FOREACH(Value& tv, json_bad) {
- tests_bad.insert(write_string(Value(tv.get_array()), true));
+ for (unsigned int idx = 0; idx < json_bad.size(); idx++) {
+ const UniValue& tv = json_bad[idx];
+ tests_bad.insert(tv.get_array().write());
}
}
@@ -598,7 +598,7 @@ BOOST_AUTO_TEST_CASE(script_build)
BOOST_FOREACH(TestBuilder& test, good) {
test.Test(true);
- std::string str = write_string(Value(test.GetJSON()), true);
+ std::string str = test.GetJSON().write();
#ifndef UPDATE_JSON_TESTS
if (tests_good.count(str) == 0) {
BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment());
@@ -608,7 +608,7 @@ BOOST_AUTO_TEST_CASE(script_build)
}
BOOST_FOREACH(TestBuilder& test, bad) {
test.Test(false);
- std::string str = write_string(Value(test.GetJSON()), true);
+ std::string str = test.GetJSON().write();
#ifndef UPDATE_JSON_TESTS
if (tests_bad.count(str) == 0) {
BOOST_CHECK_MESSAGE(false, "Missing auto script_invalid test: " + test.GetComment());
@@ -634,12 +634,11 @@ BOOST_AUTO_TEST_CASE(script_valid)
// Inner arrays are [ "scriptSig", "scriptPubKey", "flags" ]
// ... where scriptSig and scriptPubKey are stringified
// scripts.
- Array tests = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
+ UniValue tests = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- string strTest = write_string(tv, false);
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ string strTest = test.write();
if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments)
{
if (test.size() != 1) {
@@ -660,13 +659,12 @@ BOOST_AUTO_TEST_CASE(script_valid)
BOOST_AUTO_TEST_CASE(script_invalid)
{
// Scripts that should evaluate as invalid
- Array tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
+ UniValue tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- string strTest = write_string(tv, false);
- if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments)
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ string strTest = test.write();
+ if (test.size() < 3) // Allow size > 2; extra stuff ignored (useful for comments)
{
if (test.size() != 1) {
BOOST_ERROR("Bad test: " << strTest);
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index 87be2217c4..a0797d5f3f 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -16,12 +16,10 @@
#include <iostream>
#include <boost/test/unit_test.hpp>
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_writer_template.h"
-using namespace json_spirit;
-extern Array read_json(const std::string& jsondata);
+#include "univalue/univalue.h"
+
+extern UniValue read_json(const std::string& jsondata);
// Old script.cpp SignatureHash function
uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
@@ -168,12 +166,11 @@ BOOST_AUTO_TEST_CASE(sighash_test)
// Goal: check that SignatureHash generates correct hash
BOOST_AUTO_TEST_CASE(sighash_from_data)
{
- Array tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash)));
+ UniValue tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash)));
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 1) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index d12535e438..4cfdec1267 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -20,15 +20,16 @@
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
+#include <boost/assign/list_of.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/assign/list_of.hpp>
-#include "json/json_spirit_writer_template.h"
+
+#include "univalue/univalue.h"
using namespace std;
-using namespace json_spirit;
// In script_tests.cpp
-extern Array read_json(const std::string& jsondata);
+extern UniValue read_json(const std::string& jsondata);
static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of
(string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE)
@@ -88,32 +89,31 @@ BOOST_AUTO_TEST_CASE(tx_valid)
// ... where all scripts are stringified scripts.
//
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
- Array tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid)));
+ UniValue tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid)));
ScriptError err;
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- string strTest = write_string(tv, false);
- if (test[0].type() == array_type)
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ string strTest = test.write();
+ if (test[0].isArray())
{
- if (test.size() != 3 || test[1].type() != str_type || test[2].type() != str_type)
+ if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())
{
BOOST_ERROR("Bad test: " << strTest);
continue;
}
map<COutPoint, CScript> mapprevOutScriptPubKeys;
- Array inputs = test[0].get_array();
+ UniValue inputs = test[0].get_array();
bool fValid = true;
- BOOST_FOREACH(Value& input, inputs)
- {
- if (input.type() != array_type)
+ for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) {
+ const UniValue& input = inputs[inpIdx];
+ if (!input.isArray())
{
fValid = false;
break;
}
- Array vinput = input.get_array();
+ UniValue vinput = input.get_array();
if (vinput.size() != 3)
{
fValid = false;
@@ -164,32 +164,31 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
// ... where all scripts are stringified scripts.
//
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
- Array tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));
+ UniValue tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));
ScriptError err;
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- string strTest = write_string(tv, false);
- if (test[0].type() == array_type)
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ string strTest = test.write();
+ if (test[0].isArray())
{
- if (test.size() != 3 || test[1].type() != str_type || test[2].type() != str_type)
+ if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())
{
BOOST_ERROR("Bad test: " << strTest);
continue;
}
map<COutPoint, CScript> mapprevOutScriptPubKeys;
- Array inputs = test[0].get_array();
+ UniValue inputs = test[0].get_array();
bool fValid = true;
- BOOST_FOREACH(Value& input, inputs)
- {
- if (input.type() != array_type)
+ for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) {
+ const UniValue& input = inputs[inpIdx];
+ if (!input.isArray())
{
fValid = false;
break;
}
- Array vinput = input.get_array();
+ UniValue vinput = input.get_array();
if (vinput.size() != 3)
{
fValid = false;
diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp
index 8cecfbf651..16bc8d30f6 100644
--- a/src/test/univalue_tests.cpp
+++ b/src/test/univalue_tests.cpp
@@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(univalue_constructor)
double vd = -7.21;
UniValue v7(vd);
- BOOST_CHECK(v7.isNum());
+ BOOST_CHECK(v7.isReal());
BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21");
string vs("yawn");
@@ -63,6 +63,48 @@ BOOST_AUTO_TEST_CASE(univalue_constructor)
BOOST_CHECK_EQUAL(v9.getValStr(), "zappa");
}
+BOOST_AUTO_TEST_CASE(univalue_typecheck)
+{
+ UniValue v1;
+ BOOST_CHECK(v1.setNumStr("1"));
+ BOOST_CHECK(v1.isNum());
+ BOOST_CHECK_THROW(v1.get_bool(), runtime_error);
+
+ UniValue v2;
+ BOOST_CHECK(v2.setBool(true));
+ BOOST_CHECK_EQUAL(v2.get_bool(), true);
+ BOOST_CHECK_THROW(v2.get_int(), runtime_error);
+
+ UniValue v3;
+ BOOST_CHECK(v3.setNumStr("32482348723847471234"));
+ BOOST_CHECK_THROW(v3.get_int64(), runtime_error);
+ BOOST_CHECK(v3.setNumStr("1000"));
+ BOOST_CHECK_EQUAL(v3.get_int64(), 1000);
+
+ UniValue v4;
+ BOOST_CHECK(v4.setNumStr("2147483648"));
+ BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648);
+ BOOST_CHECK_THROW(v4.get_int(), runtime_error);
+ BOOST_CHECK(v4.setNumStr("1000"));
+ BOOST_CHECK_EQUAL(v4.get_int(), 1000);
+ BOOST_CHECK_THROW(v4.get_str(), runtime_error);
+ BOOST_CHECK_EQUAL(v4.get_real(), 1000);
+ BOOST_CHECK_THROW(v4.get_array(), runtime_error);
+ BOOST_CHECK_THROW(v4.getKeys(), runtime_error);
+ BOOST_CHECK_THROW(v4.getValues(), runtime_error);
+ BOOST_CHECK_THROW(v4.get_obj(), runtime_error);
+
+ UniValue v5;
+ BOOST_CHECK(v5.read("[true, 10]"));
+ BOOST_CHECK_NO_THROW(v5.get_array());
+ std::vector<UniValue> vals = v5.getValues();
+ BOOST_CHECK_THROW(vals[0].get_int(), runtime_error);
+ BOOST_CHECK_EQUAL(vals[0].get_bool(), true);
+
+ BOOST_CHECK_EQUAL(vals[1].get_int(), 10);
+ BOOST_CHECK_THROW(vals[1].get_bool(), runtime_error);
+}
+
BOOST_AUTO_TEST_CASE(univalue_set)
{
UniValue v(UniValue::VSTR, "foo");
@@ -72,20 +114,20 @@ BOOST_AUTO_TEST_CASE(univalue_set)
BOOST_CHECK(v.setObject());
BOOST_CHECK(v.isObject());
- BOOST_CHECK_EQUAL(v.count(), 0);
+ BOOST_CHECK_EQUAL(v.size(), 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_EQUAL(v.size(), 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(v.isReal());
BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");
BOOST_CHECK(v.setInt((int)1023));
@@ -145,7 +187,7 @@ BOOST_AUTO_TEST_CASE(univalue_array)
BOOST_CHECK(arr.push_backV(vec));
BOOST_CHECK_EQUAL(arr.empty(), false);
- BOOST_CHECK_EQUAL(arr.count(), 5);
+ BOOST_CHECK_EQUAL(arr.size(), 5);
BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023");
BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy");
@@ -157,7 +199,7 @@ BOOST_AUTO_TEST_CASE(univalue_array)
arr.clear();
BOOST_CHECK(arr.empty());
- BOOST_CHECK_EQUAL(arr.count(), 0);
+ BOOST_CHECK_EQUAL(arr.size(), 0);
}
BOOST_AUTO_TEST_CASE(univalue_object)
@@ -197,7 +239,7 @@ BOOST_AUTO_TEST_CASE(univalue_object)
BOOST_CHECK(obj.pushKVs(obj2));
BOOST_CHECK_EQUAL(obj.empty(), false);
- BOOST_CHECK_EQUAL(obj.count(), 9);
+ BOOST_CHECK_EQUAL(obj.size(), 9);
BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100");
BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John");
@@ -230,7 +272,7 @@ BOOST_AUTO_TEST_CASE(univalue_object)
objTypes["distance"] = UniValue::VNUM;
objTypes["time"] = UniValue::VNUM;
objTypes["calories"] = UniValue::VNUM;
- objTypes["temperature"] = UniValue::VNUM;
+ objTypes["temperature"] = UniValue::VREAL;
objTypes["cat1"] = UniValue::VNUM;
objTypes["cat2"] = UniValue::VNUM;
BOOST_CHECK(obj.checkObject(objTypes));
@@ -240,11 +282,11 @@ BOOST_AUTO_TEST_CASE(univalue_object)
obj.clear();
BOOST_CHECK(obj.empty());
- BOOST_CHECK_EQUAL(obj.count(), 0);
+ BOOST_CHECK_EQUAL(obj.size(), 0);
}
static const char *json1 =
-"[1.1,{\"key1\":\"str\",\"key2\":800,\"key3\":{\"name\":\"martian\"}}]";
+"[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian http://test.com\"}}]";
BOOST_AUTO_TEST_CASE(univalue_readwrite)
{
@@ -255,16 +297,18 @@ BOOST_AUTO_TEST_CASE(univalue_readwrite)
BOOST_CHECK(v.read(strJson1));
BOOST_CHECK(v.isArray());
- BOOST_CHECK_EQUAL(v.count(), 2);
+ BOOST_CHECK_EQUAL(v.size(), 2);
- BOOST_CHECK_EQUAL(v[0].getValStr(), "1.1");
+ BOOST_CHECK_EQUAL(v[0].getValStr(), "1.10000000");
UniValue obj = v[1];
BOOST_CHECK(obj.isObject());
- BOOST_CHECK_EQUAL(obj.count(), 3);
+ BOOST_CHECK_EQUAL(obj.size(), 3);
BOOST_CHECK(obj["key1"].isStr());
- BOOST_CHECK_EQUAL(obj["key1"].getValStr(), "str");
+ std::string correctValue("str");
+ correctValue.push_back('\0');
+ BOOST_CHECK_EQUAL(obj["key1"].getValStr(), correctValue);
BOOST_CHECK(obj["key2"].isNum());
BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800");
BOOST_CHECK(obj["key3"].isObject());
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 3309e2e387..5cb5894251 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -146,29 +146,27 @@ BOOST_AUTO_TEST_CASE(util_GetArg)
BOOST_AUTO_TEST_CASE(util_FormatMoney)
{
- BOOST_CHECK_EQUAL(FormatMoney(0, false), "0.00");
- BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789, false), "12345.6789");
- BOOST_CHECK_EQUAL(FormatMoney(COIN, true), "+1.00");
- BOOST_CHECK_EQUAL(FormatMoney(-COIN, false), "-1.00");
- BOOST_CHECK_EQUAL(FormatMoney(-COIN, true), "-1.00");
-
- BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000, false), "100000000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000, false), "10000000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000, false), "1000000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*100000, false), "100000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*10000, false), "10000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*1000, false), "1000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*100, false), "100.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*10, false), "10.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN, false), "1.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/10, false), "0.10");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/100, false), "0.01");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/1000, false), "0.001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/10000, false), "0.0001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/100000, false), "0.00001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000, false), "0.000001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000, false), "0.0000001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000, false), "0.00000001");
+ BOOST_CHECK_EQUAL(FormatMoney(0), "0.00");
+ BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789), "12345.6789");
+ BOOST_CHECK_EQUAL(FormatMoney(-COIN), "-1.00");
+
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000), "100000000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000), "10000000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000), "1000000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*100000), "100000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*10000), "10000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*1000), "1000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*100), "100.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*10), "10.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN), "1.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/10), "0.10");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/100), "0.01");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/1000), "0.001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/10000), "0.0001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/100000), "0.00001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000), "0.000001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000), "0.0000001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000), "0.00000001");
}
BOOST_AUTO_TEST_CASE(util_ParseMoney)
@@ -322,9 +320,16 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32)
BOOST_CHECK(ParseInt32("-2147483648", &n) && n == -2147483648);
BOOST_CHECK(ParseInt32("-1234", &n) && n == -1234);
// Invalid values
+ BOOST_CHECK(!ParseInt32("", &n));
+ BOOST_CHECK(!ParseInt32(" 1", &n)); // no padding inside
+ BOOST_CHECK(!ParseInt32("1 ", &n));
BOOST_CHECK(!ParseInt32("1a", &n));
BOOST_CHECK(!ParseInt32("aap", &n));
BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
+ BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
+ const char test_bytes[] = {'1', 0, '1'};
+ std::string teststr(test_bytes, sizeof(test_bytes));
+ BOOST_CHECK(!ParseInt32(teststr, &n)); // no embedded NULs
// Overflow and underflow
BOOST_CHECK(!ParseInt32("-2147483649", NULL));
BOOST_CHECK(!ParseInt32("2147483648", NULL));
@@ -332,6 +337,64 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32)
BOOST_CHECK(!ParseInt32("32482348723847471234", NULL));
}
+BOOST_AUTO_TEST_CASE(test_ParseInt64)
+{
+ int64_t n;
+ // Valid values
+ BOOST_CHECK(ParseInt64("1234", NULL));
+ BOOST_CHECK(ParseInt64("0", &n) && n == 0LL);
+ BOOST_CHECK(ParseInt64("1234", &n) && n == 1234LL);
+ BOOST_CHECK(ParseInt64("01234", &n) && n == 1234LL); // no octal
+ BOOST_CHECK(ParseInt64("2147483647", &n) && n == 2147483647LL);
+ BOOST_CHECK(ParseInt64("-2147483648", &n) && n == -2147483648LL);
+ BOOST_CHECK(ParseInt64("9223372036854775807", &n) && n == (int64_t)9223372036854775807);
+ BOOST_CHECK(ParseInt64("-9223372036854775808", &n) && n == (int64_t)-9223372036854775807-1);
+ BOOST_CHECK(ParseInt64("-1234", &n) && n == -1234LL);
+ // Invalid values
+ BOOST_CHECK(!ParseInt64("", &n));
+ BOOST_CHECK(!ParseInt64(" 1", &n)); // no padding inside
+ BOOST_CHECK(!ParseInt64("1 ", &n));
+ BOOST_CHECK(!ParseInt64("1a", &n));
+ BOOST_CHECK(!ParseInt64("aap", &n));
+ BOOST_CHECK(!ParseInt64("0x1", &n)); // no hex
+ const char test_bytes[] = {'1', 0, '1'};
+ std::string teststr(test_bytes, sizeof(test_bytes));
+ BOOST_CHECK(!ParseInt64(teststr, &n)); // no embedded NULs
+ // Overflow and underflow
+ BOOST_CHECK(!ParseInt64("-9223372036854775809", NULL));
+ BOOST_CHECK(!ParseInt64("9223372036854775808", NULL));
+ BOOST_CHECK(!ParseInt64("-32482348723847471234", NULL));
+ BOOST_CHECK(!ParseInt64("32482348723847471234", NULL));
+}
+
+BOOST_AUTO_TEST_CASE(test_ParseDouble)
+{
+ double n;
+ // Valid values
+ BOOST_CHECK(ParseDouble("1234", NULL));
+ BOOST_CHECK(ParseDouble("0", &n) && n == 0.0);
+ BOOST_CHECK(ParseDouble("1234", &n) && n == 1234.0);
+ BOOST_CHECK(ParseDouble("01234", &n) && n == 1234.0); // no octal
+ BOOST_CHECK(ParseDouble("2147483647", &n) && n == 2147483647.0);
+ BOOST_CHECK(ParseDouble("-2147483648", &n) && n == -2147483648.0);
+ BOOST_CHECK(ParseDouble("-1234", &n) && n == -1234.0);
+ BOOST_CHECK(ParseDouble("1e6", &n) && n == 1e6);
+ BOOST_CHECK(ParseDouble("-1e6", &n) && n == -1e6);
+ // Invalid values
+ BOOST_CHECK(!ParseDouble("", &n));
+ BOOST_CHECK(!ParseDouble(" 1", &n)); // no padding inside
+ BOOST_CHECK(!ParseDouble("1 ", &n));
+ BOOST_CHECK(!ParseDouble("1a", &n));
+ BOOST_CHECK(!ParseDouble("aap", &n));
+ BOOST_CHECK(!ParseDouble("0x1", &n)); // no hex
+ const char test_bytes[] = {'1', 0, '1'};
+ std::string teststr(test_bytes, sizeof(test_bytes));
+ BOOST_CHECK(!ParseDouble(teststr, &n)); // no embedded NULs
+ // Overflow and underflow
+ BOOST_CHECK(!ParseDouble("-1e10000", NULL));
+ BOOST_CHECK(!ParseDouble("1e10000", NULL));
+}
+
BOOST_AUTO_TEST_CASE(test_FormatParagraph)
{
BOOST_CHECK_EQUAL(FormatParagraph("", 79, 0), "");
diff --git a/src/txdb.cpp b/src/txdb.cpp
index df9ff8d8c9..935b784676 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -147,7 +147,10 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
}
- stats.nHeight = mapBlockIndex.find(GetBestBlock())->second->nHeight;
+ {
+ LOCK(cs_main);
+ stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight;
+ }
stats.hashSerialized = ss.GetHash();
stats.nTotalAmount = nTotalAmount;
return true;
diff --git a/src/univalue/gen.cpp b/src/univalue/gen.cpp
index abebe88634..5e5a4d4aed 100644
--- a/src/univalue/gen.cpp
+++ b/src/univalue/gen.cpp
@@ -22,7 +22,6 @@ static void initJsonEscape()
{
escapes[(int)'"'] = "\\\"";
escapes[(int)'\\'] = "\\\\";
- escapes[(int)'/'] = "\\/";
escapes[(int)'\b'] = "\\b";
escapes[(int)'\f'] = "\\f";
escapes[(int)'\n'] = "\\n";
diff --git a/src/univalue/univalue.cpp b/src/univalue/univalue.cpp
index 4e445a542a..6920c44c96 100644
--- a/src/univalue/univalue.cpp
+++ b/src/univalue/univalue.cpp
@@ -4,12 +4,17 @@
#include <stdint.h>
#include <ctype.h>
+#include <iomanip>
#include <sstream>
+#include <stdexcept> // std::runtime_error
+
#include "univalue.h"
+#include "utilstrencodings.h" // ParseXX
+
using namespace std;
-static const UniValue nullValue;
+const UniValue NullUniValue;
void UniValue::clear()
{
@@ -78,9 +83,11 @@ bool UniValue::setFloat(double val)
string s;
ostringstream oss;
- oss << val;
+ oss << std::setprecision(16) << val;
- return setNumStr(oss.str());
+ bool ret = setNumStr(oss.str());
+ typ = VREAL;
+ return ret;
}
bool UniValue::setStr(const string& val_)
@@ -175,11 +182,11 @@ bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t)
const UniValue& UniValue::operator[](const std::string& key) const
{
if (typ != VOBJ)
- return nullValue;
+ return NullUniValue;
int index = findKey(key);
if (index < 0)
- return nullValue;
+ return NullUniValue;
return values[index];
}
@@ -187,9 +194,9 @@ const UniValue& UniValue::operator[](const std::string& key) const
const UniValue& UniValue::operator[](unsigned int index) const
{
if (typ != VOBJ && typ != VARR)
- return nullValue;
+ return NullUniValue;
if (index >= values.size())
- return nullValue;
+ return NullUniValue;
return values[index];
}
@@ -203,9 +210,95 @@ const char *uvTypeName(UniValue::VType t)
case UniValue::VARR: return "array";
case UniValue::VSTR: return "string";
case UniValue::VNUM: return "number";
+ case UniValue::VREAL: return "number";
}
// not reached
return NULL;
}
+const UniValue& find_value( const UniValue& obj, const std::string& name)
+{
+ for (unsigned int i = 0; i < obj.keys.size(); i++)
+ {
+ if( obj.keys[i] == name )
+ {
+ return obj.values[i];
+ }
+ }
+
+ return NullUniValue;
+}
+
+std::vector<std::string> UniValue::getKeys() const
+{
+ if (typ != VOBJ)
+ throw std::runtime_error("JSON value is not an object as expected");
+ return keys;
+}
+
+std::vector<UniValue> UniValue::getValues() const
+{
+ if (typ != VOBJ && typ != VARR)
+ throw std::runtime_error("JSON value is not an object or array as expected");
+ return values;
+}
+
+bool UniValue::get_bool() const
+{
+ if (typ != VBOOL)
+ throw std::runtime_error("JSON value is not a boolean as expected");
+ return getBool();
+}
+
+std::string UniValue::get_str() const
+{
+ if (typ != VSTR)
+ throw std::runtime_error("JSON value is not a string as expected");
+ return getValStr();
+}
+
+int UniValue::get_int() const
+{
+ if (typ != VNUM)
+ throw std::runtime_error("JSON value is not an integer as expected");
+ int32_t retval;
+ if (!ParseInt32(getValStr(), &retval))
+ throw std::runtime_error("JSON integer out of range");
+ return retval;
+}
+
+int64_t UniValue::get_int64() const
+{
+ if (typ != VNUM)
+ throw std::runtime_error("JSON value is not an integer as expected");
+ int64_t retval;
+ if (!ParseInt64(getValStr(), &retval))
+ throw std::runtime_error("JSON integer out of range");
+ return retval;
+}
+
+double UniValue::get_real() const
+{
+ if (typ != VREAL && typ != VNUM)
+ throw std::runtime_error("JSON value is not a number as expected");
+ double retval;
+ if (!ParseDouble(getValStr(), &retval))
+ throw std::runtime_error("JSON double out of range");
+ return retval;
+}
+
+const UniValue& UniValue::get_obj() const
+{
+ if (typ != VOBJ)
+ throw std::runtime_error("JSON value is not an object as expected");
+ return *this;
+}
+
+const UniValue& UniValue::get_array() const
+{
+ if (typ != VARR)
+ throw std::runtime_error("JSON value is not an array as expected");
+ return *this;
+}
+
diff --git a/src/univalue/univalue.h b/src/univalue/univalue.h
index 88d73b8c64..54239741e2 100644
--- a/src/univalue/univalue.h
+++ b/src/univalue/univalue.h
@@ -11,9 +11,12 @@
#include <map>
#include <cassert>
+#include <sstream> // .get_int64()
+#include <utility> // std::pair
+
class UniValue {
public:
- enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
+ enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VREAL, VBOOL, };
UniValue() { typ = VNULL; }
UniValue(UniValue::VType initialType, const std::string& initialStr = "") {
@@ -26,6 +29,9 @@ public:
UniValue(int64_t val_) {
setInt(val_);
}
+ UniValue(bool val_) {
+ setBool(val_);
+ }
UniValue(int val_) {
setInt(val_);
}
@@ -55,10 +61,10 @@ public:
bool setObject();
enum VType getType() const { return typ; }
- std::string getValStr() const { return val; }
+ const std::string& getValStr() const { return val; }
bool empty() const { return (values.size() == 0); }
- size_t count() const { return values.size(); }
+ size_t size() const { return values.size(); }
bool getBool() const { return isTrue(); }
bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes);
@@ -68,10 +74,11 @@ public:
bool isNull() const { return (typ == VNULL); }
bool isTrue() const { return (typ == VBOOL) && (val == "1"); }
- bool isFalse() const { return (!isTrue()); }
+ bool isFalse() const { return (typ == VBOOL) && (val != "1"); }
bool isBool() const { return (typ == VBOOL); }
bool isStr() const { return (typ == VSTR); }
bool isNum() const { return (typ == VNUM); }
+ bool isReal() const { return (typ == VREAL); }
bool isArray() const { return (typ == VARR); }
bool isObject() const { return (typ == VOBJ); }
@@ -130,8 +137,91 @@ private:
int findKey(const std::string& key) const;
void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
+
+public:
+ // Strict type-specific getters, these throw std::runtime_error if the
+ // value is of unexpected type
+ std::vector<std::string> getKeys() const;
+ std::vector<UniValue> getValues() const;
+ bool get_bool() const;
+ std::string get_str() const;
+ int get_int() const;
+ int64_t get_int64() const;
+ double get_real() const;
+ const UniValue& get_obj() const;
+ const UniValue& get_array() const;
+
+ enum VType type() const { return getType(); }
+ bool push_back(std::pair<std::string,UniValue> pear) {
+ return pushKV(pear.first, pear.second);
+ }
+ friend const UniValue& find_value( const UniValue& obj, const std::string& name);
};
+//
+// The following were added for compatibility with json_spirit.
+// Most duplicate other methods, and should be removed.
+//
+static inline std::pair<std::string,UniValue> Pair(const char *cKey, const char *cVal)
+{
+ std::string key(cKey);
+ UniValue uVal(cVal);
+ return std::make_pair(key, uVal);
+}
+
+static inline std::pair<std::string,UniValue> Pair(const char *cKey, std::string strVal)
+{
+ std::string key(cKey);
+ UniValue uVal(strVal);
+ return std::make_pair(key, uVal);
+}
+
+static inline std::pair<std::string,UniValue> Pair(const char *cKey, uint64_t u64Val)
+{
+ std::string key(cKey);
+ UniValue uVal(u64Val);
+ return std::make_pair(key, uVal);
+}
+
+static inline std::pair<std::string,UniValue> Pair(const char *cKey, int64_t i64Val)
+{
+ std::string key(cKey);
+ UniValue uVal(i64Val);
+ return std::make_pair(key, uVal);
+}
+
+static inline std::pair<std::string,UniValue> Pair(const char *cKey, bool iVal)
+{
+ std::string key(cKey);
+ UniValue uVal(iVal);
+ return std::make_pair(key, uVal);
+}
+
+static inline std::pair<std::string,UniValue> Pair(const char *cKey, int iVal)
+{
+ std::string key(cKey);
+ UniValue uVal(iVal);
+ return std::make_pair(key, uVal);
+}
+
+static inline std::pair<std::string,UniValue> Pair(const char *cKey, double dVal)
+{
+ std::string key(cKey);
+ UniValue uVal(dVal);
+ return std::make_pair(key, uVal);
+}
+
+static inline std::pair<std::string,UniValue> Pair(const char *cKey, const UniValue& uVal)
+{
+ std::string key(cKey);
+ return std::make_pair(key, uVal);
+}
+
+static inline std::pair<std::string,UniValue> Pair(std::string key, const UniValue& uVal)
+{
+ return std::make_pair(key, uVal);
+}
+
enum jtokentype {
JTOK_ERR = -1,
JTOK_NONE = 0, // eof
@@ -152,4 +242,8 @@ extern enum jtokentype getJsonToken(std::string& tokenVal,
unsigned int& consumed, const char *raw);
extern const char *uvTypeName(UniValue::VType t);
+extern const UniValue NullUniValue;
+
+const UniValue& find_value( const UniValue& obj, const std::string& name);
+
#endif // BITCOIN_UNIVALUE_UNIVALUE_H
diff --git a/src/univalue/univalue_escapes.h b/src/univalue/univalue_escapes.h
index 0514118285..4133b24ca1 100644
--- a/src/univalue/univalue_escapes.h
+++ b/src/univalue/univalue_escapes.h
@@ -49,7 +49,7 @@ static const char *escapes[256] = {
NULL,
NULL,
NULL,
- "\\/",
+ NULL,
NULL,
NULL,
NULL,
diff --git a/src/univalue/univalue_read.cpp b/src/univalue/univalue_read.cpp
index 5cea778996..261771811d 100644
--- a/src/univalue/univalue_read.cpp
+++ b/src/univalue/univalue_read.cpp
@@ -188,25 +188,22 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
case 't': valStr += "\t"; break;
case 'u': {
- char buf[4] = {0,0,0,0};
- char *last = &buf[0];
unsigned int codepoint;
if (hatoui(raw + 1, raw + 1 + 4, codepoint) !=
raw + 1 + 4)
return JTOK_ERR;
if (codepoint <= 0x7f)
- *last = (char)codepoint;
+ valStr.push_back((char)codepoint);
else if (codepoint <= 0x7FF) {
- *last++ = (char)(0xC0 | (codepoint >> 6));
- *last = (char)(0x80 | (codepoint & 0x3F));
+ valStr.push_back((char)(0xC0 | (codepoint >> 6)));
+ valStr.push_back((char)(0x80 | (codepoint & 0x3F)));
} else if (codepoint <= 0xFFFF) {
- *last++ = (char)(0xE0 | (codepoint >> 12));
- *last++ = (char)(0x80 | ((codepoint >> 6) & 0x3F));
- *last = (char)(0x80 | (codepoint & 0x3F));
+ valStr.push_back((char)(0xE0 | (codepoint >> 12)));
+ valStr.push_back((char)(0x80 | ((codepoint >> 6) & 0x3F)));
+ valStr.push_back((char)(0x80 | (codepoint & 0x3F)));
}
- valStr += buf;
raw += 4;
break;
}
diff --git a/src/univalue/univalue_write.cpp b/src/univalue/univalue_write.cpp
index 9a1d364c95..d360c253b0 100644
--- a/src/univalue/univalue_write.cpp
+++ b/src/univalue/univalue_write.cpp
@@ -3,6 +3,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <ctype.h>
+#include <iomanip>
+#include <sstream>
#include <stdio.h>
#include "univalue.h"
#include "univalue_escapes.h"
@@ -59,6 +61,13 @@ string UniValue::write(unsigned int prettyIndent,
case VSTR:
s += "\"" + json_escape(val) + "\"";
break;
+ case VREAL:
+ {
+ std::stringstream ss;
+ ss << std::showpoint << std::fixed << std::setprecision(8) << get_real();
+ s += ss.str();
+ }
+ break;
case VNUM:
s += val;
break;
diff --git a/src/util.cpp b/src/util.cpp
index 33b5ee9500..da5821e530 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -702,7 +702,7 @@ boost::filesystem::path GetTempPath() {
#endif
}
-void runCommand(std::string strCommand)
+void runCommand(const std::string& strCommand)
{
int nErr = ::system(strCommand.c_str());
if (nErr)
diff --git a/src/util.h b/src/util.h
index 4cc0faf4d7..6ec81698ea 100644
--- a/src/util.h
+++ b/src/util.h
@@ -126,7 +126,7 @@ boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
boost::filesystem::path GetTempPath();
void ShrinkDebugFile();
-void runCommand(std::string strCommand);
+void runCommand(const std::string& strCommand);
inline bool IsSwitchChar(char c)
{
diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp
index 2fbc048878..0f3203432f 100644
--- a/src/utilmoneystr.cpp
+++ b/src/utilmoneystr.cpp
@@ -11,7 +11,7 @@
using namespace std;
-string FormatMoney(const CAmount& n, bool fPlus)
+std::string FormatMoney(const CAmount& n)
{
// Note: not using straight sprintf here because we do NOT want
// localized number formatting.
@@ -29,8 +29,6 @@ string FormatMoney(const CAmount& n, bool fPlus)
if (n < 0)
str.insert((unsigned int)0, 1, '-');
- else if (fPlus && n > 0)
- str.insert((unsigned int)0, 1, '+');
return str;
}
diff --git a/src/utilmoneystr.h b/src/utilmoneystr.h
index cd9b04810d..99c3ba8306 100644
--- a/src/utilmoneystr.h
+++ b/src/utilmoneystr.h
@@ -14,7 +14,7 @@
#include "amount.h"
-std::string FormatMoney(const CAmount& n, bool fPlus=false);
+std::string FormatMoney(const CAmount& n);
bool ParseMoney(const std::string& str, CAmount& nRet);
bool ParseMoney(const char* pszIn, CAmount& nRet);
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp
index c15bddc6fb..7d1de7d6a8 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -416,12 +416,25 @@ string DecodeBase32(const string& str)
return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size());
}
+static bool ParsePrechecks(const std::string& str)
+{
+ if (str.empty()) // No empty string allowed
+ return false;
+ if (str.size() >= 1 && (isspace(str[0]) || isspace(str[str.size()-1]))) // No padding allowed
+ return false;
+ if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed
+ return false;
+ return true;
+}
+
bool ParseInt32(const std::string& str, int32_t *out)
{
+ if (!ParsePrechecks(str))
+ return false;
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;
+ if(out) *out = (int32_t)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.
@@ -430,7 +443,35 @@ bool ParseInt32(const std::string& str, int32_t *out)
n <= std::numeric_limits<int32_t>::max();
}
-std::string FormatParagraph(const std::string in, size_t width, size_t indent)
+bool ParseInt64(const std::string& str, int64_t *out)
+{
+ if (!ParsePrechecks(str))
+ return false;
+ char *endp = NULL;
+ errno = 0; // strtoll will not set errno if valid
+ long long int n = strtoll(str.c_str(), &endp, 10);
+ if(out) *out = (int64_t)n;
+ // Note that strtoll returns a *long 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 *int64_t*.
+ return endp && *endp == 0 && !errno &&
+ n >= std::numeric_limits<int64_t>::min() &&
+ n <= std::numeric_limits<int64_t>::max();
+}
+
+bool ParseDouble(const std::string& str, double *out)
+{
+ if (!ParsePrechecks(str))
+ return false;
+ if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
+ return false;
+ char *endp = NULL;
+ errno = 0; // strtod will not set errno if valid
+ double n = strtod(str.c_str(), &endp);
+ if(out) *out = n;
+ return endp && *endp == 0 && !errno;
+}
+
+std::string FormatParagraph(const std::string& in, size_t width, size_t indent)
{
std::stringstream out;
size_t col = 0;
diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h
index b0edd8b542..58329b51bb 100644
--- a/src/utilstrencodings.h
+++ b/src/utilstrencodings.h
@@ -49,6 +49,20 @@ int atoi(const std::string& str);
*/
bool ParseInt32(const std::string& str, int32_t *out);
+/**
+ * Convert string to signed 64-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 occurred.
+ */
+bool ParseInt64(const std::string& str, int64_t *out);
+
+/**
+ * Convert string to double with strict parse error feedback.
+ * @returns true if the entire string could be parsed as valid double,
+ * false if not the entire string could be parsed or when overflow or underflow occurred.
+ */
+bool ParseDouble(const std::string& str, double *out);
+
template<typename T>
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
{
@@ -74,11 +88,11 @@ 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);
+std::string FormatParagraph(const std::string& in, size_t width = 79, size_t indent = 0);
/**
* Timing-attack-resistant comparison.
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index aa9aefb0de..0532da5f37 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -14,7 +14,6 @@ CMainSignals& GetMainSignals()
void RegisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2));
- g_signals.EraseTransaction.connect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1));
g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
@@ -28,7 +27,6 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
- g_signals.EraseTransaction.disconnect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1));
g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2));
}
@@ -38,7 +36,6 @@ void UnregisterAllValidationInterfaces() {
g_signals.Inventory.disconnect_all_slots();
g_signals.SetBestChain.disconnect_all_slots();
g_signals.UpdatedTransaction.disconnect_all_slots();
- g_signals.EraseTransaction.disconnect_all_slots();
g_signals.SyncTransaction.disconnect_all_slots();
}
diff --git a/src/validationinterface.h b/src/validationinterface.h
index 2a4c7ecceb..a911d1efeb 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -29,7 +29,6 @@ void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL);
class CValidationInterface {
protected:
virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {}
- virtual void EraseFromWallet(const uint256 &hash) {}
virtual void SetBestChain(const CBlockLocator &locator) {}
virtual void UpdatedTransaction(const uint256 &hash) {}
virtual void Inventory(const uint256 &hash) {}
@@ -43,8 +42,6 @@ protected:
struct CMainSignals {
/** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */
boost::signals2::signal<void (const CTransaction &, const CBlock *)> SyncTransaction;
- /** Notifies listeners of an erased transaction (currently disabled, requires transaction replacement). */
- boost::signals2::signal<void (const uint256 &)> EraseTransaction;
/** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */
boost::signals2::signal<void (const uint256 &)> UpdatedTransaction;
/** Notifies listeners of a new active block chain. */
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 53cfcf0961..e5bc653c33 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -43,7 +43,7 @@ void CDBEnv::EnvShutdown()
if (ret != 0)
LogPrintf("CDBEnv::EnvShutdown: Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret));
if (!fMockDb)
- DbEnv(0).remove(path.string().c_str(), 0);
+ DbEnv(0).remove(strPath.c_str(), 0);
}
void CDBEnv::Reset()
@@ -78,10 +78,10 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn)
boost::this_thread::interruption_point();
- path = pathIn;
- boost::filesystem::path pathLogDir = path / "database";
+ strPath = pathIn.string();
+ boost::filesystem::path pathLogDir = pathIn / "database";
TryCreateDirectory(pathLogDir);
- boost::filesystem::path pathErrorFile = path / "db.log";
+ boost::filesystem::path pathErrorFile = pathIn / "db.log";
LogPrintf("CDBEnv::Open: LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string());
unsigned int nEnvFlags = 0;
@@ -98,7 +98,7 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn)
dbenv->set_flags(DB_AUTO_COMMIT, 1);
dbenv->set_flags(DB_TXN_WRITE_NOSYNC, 1);
dbenv->log_set_config(DB_LOG_AUTO_REMOVE, 1);
- int ret = dbenv->open(path.string().c_str(),
+ int ret = dbenv->open(strPath.c_str(),
DB_CREATE |
DB_INIT_LOCK |
DB_INIT_LOG |
@@ -455,7 +455,7 @@ void CDBEnv::Flush(bool fShutdown)
dbenv->log_archive(&listp, DB_ARCH_REMOVE);
Close();
if (!fMockDb)
- boost::filesystem::remove_all(path / "database");
+ boost::filesystem::remove_all(boost::filesystem::path(strPath) / "database");
}
}
}
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 2df6f6e5a9..64071caa3a 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -27,7 +27,9 @@ class CDBEnv
private:
bool fDbEnvInit;
bool fMockDb;
- boost::filesystem::path path;
+ // Don't change into boost::filesystem::path, as that can result in
+ // shutdown problems/crashes caused by a static initialized internal pointer.
+ std::string strPath;
void EnvShutdown();
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index ab951d1d7d..5f800474a0 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -19,9 +19,8 @@
#include <boost/algorithm/string.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
-#include "json/json_spirit_value.h"
+#include "univalue/univalue.h"
-using namespace json_spirit;
using namespace std;
void EnsureWalletIsUnlocked();
@@ -70,10 +69,10 @@ std::string DecodeDumpString(const std::string &str) {
return ret.str();
}
-Value importprivkey(const Array& params, bool fHelp)
+UniValue importprivkey(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 3)
throw runtime_error(
@@ -95,6 +94,9 @@ Value importprivkey(const Array& params, bool fHelp)
+ HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
);
+ if (fPruneMode)
+ throw JSONRPCError(RPC_WALLET_ERROR, "Importing keys is disabled in pruned mode");
+
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked();
@@ -126,7 +128,7 @@ Value importprivkey(const Array& params, bool fHelp)
// Don't throw error in case a key is already there
if (pwalletMain->HaveKey(vchAddress))
- return Value::null;
+ return NullUniValue;
pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1;
@@ -141,13 +143,13 @@ Value importprivkey(const Array& params, bool fHelp)
}
}
- return Value::null;
+ return NullUniValue;
}
-Value importaddress(const Array& params, bool fHelp)
+UniValue importaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 3)
throw runtime_error(
@@ -167,6 +169,9 @@ Value importaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false")
);
+ if (fPruneMode)
+ throw JSONRPCError(RPC_WALLET_ERROR, "Importing addresses is disabled in pruned mode");
+
LOCK2(cs_main, pwalletMain->cs_wallet);
CScript script;
@@ -200,7 +205,7 @@ Value importaddress(const Array& params, bool fHelp)
// Don't throw error in case an address is already there
if (pwalletMain->HaveWatchOnly(script))
- return Value::null;
+ return NullUniValue;
pwalletMain->MarkDirty();
@@ -214,13 +219,13 @@ Value importaddress(const Array& params, bool fHelp)
}
}
- return Value::null;
+ return NullUniValue;
}
-Value importwallet(const Array& params, bool fHelp)
+UniValue importwallet(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -237,6 +242,9 @@ Value importwallet(const Array& params, bool fHelp)
+ HelpExampleRpc("importwallet", "\"test\"")
);
+ if (fPruneMode)
+ throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode");
+
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked();
@@ -318,13 +326,13 @@ Value importwallet(const Array& params, bool fHelp)
if (!fGood)
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");
- return Value::null;
+ return NullUniValue;
}
-Value dumpprivkey(const Array& params, bool fHelp)
+UniValue dumpprivkey(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -359,10 +367,10 @@ Value dumpprivkey(const Array& params, bool fHelp)
}
-Value dumpwallet(const Array& params, bool fHelp)
+UniValue dumpwallet(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -421,5 +429,5 @@ Value dumpwallet(const Array& params, bool fHelp)
file << "\n";
file << "# End of dump\n";
file.close();
- return Value::null;
+ return NullUniValue;
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 3f55b04273..8d88933878 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -21,11 +21,9 @@
#include <boost/assign/list_of.hpp>
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_value.h"
+#include "univalue/univalue.h"
using namespace std;
-using namespace json_spirit;
int64_t nWalletUnlockTime;
static CCriticalSection cs_nWalletUnlockTime;
@@ -55,7 +53,7 @@ void EnsureWalletIsUnlocked()
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
}
-void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
+void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
{
int confirms = wtx.GetDepthInMainChain();
entry.push_back(Pair("confirmations", confirms));
@@ -69,7 +67,7 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
}
uint256 hash = wtx.GetHash();
entry.push_back(Pair("txid", hash.GetHex()));
- Array conflicts;
+ UniValue conflicts(UniValue::VARR);
BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
conflicts.push_back(conflict.GetHex());
entry.push_back(Pair("walletconflicts", conflicts));
@@ -79,7 +77,7 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
entry.push_back(Pair(item.first, item.second));
}
-string AccountFromValue(const Value& value)
+string AccountFromValue(const UniValue& value)
{
string strAccount = value.get_str();
if (strAccount == "*")
@@ -87,10 +85,10 @@ string AccountFromValue(const Value& value)
return strAccount;
}
-Value getnewaddress(const Array& params, bool fHelp)
+UniValue getnewaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 1)
throw runtime_error(
@@ -166,10 +164,10 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
return CBitcoinAddress(account.vchPubKey.GetID());
}
-Value getaccountaddress(const Array& params, bool fHelp)
+UniValue getaccountaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -191,17 +189,17 @@ Value getaccountaddress(const Array& params, bool fHelp)
// Parse the account first so we don't generate a key if there's an error
string strAccount = AccountFromValue(params[0]);
- Value ret;
+ UniValue ret(UniValue::VSTR);
ret = GetAccountAddress(strAccount).ToString();
return ret;
}
-Value getrawchangeaddress(const Array& params, bool fHelp)
+UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 1)
throw runtime_error(
@@ -233,10 +231,10 @@ Value getrawchangeaddress(const Array& params, bool fHelp)
}
-Value setaccount(const Array& params, bool fHelp)
+UniValue setaccount(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -275,14 +273,14 @@ Value setaccount(const Array& params, bool fHelp)
else
throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
- return Value::null;
+ return NullUniValue;
}
-Value getaccount(const Array& params, bool fHelp)
+UniValue getaccount(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -311,10 +309,10 @@ Value getaccount(const Array& params, bool fHelp)
}
-Value getaddressesbyaccount(const Array& params, bool fHelp)
+UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -337,7 +335,7 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
string strAccount = AccountFromValue(params[0]);
// Find all addresses that have the given account
- Array ret;
+ UniValue ret(UniValue::VARR);
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
{
const CBitcoinAddress& address = item.first;
@@ -379,10 +377,10 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
}
-Value sendtoaddress(const Array& params, bool fHelp)
+UniValue sendtoaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 2 || params.size() > 5)
throw runtime_error(
@@ -416,12 +414,14 @@ Value sendtoaddress(const Array& params, bool fHelp)
// Amount
CAmount nAmount = AmountFromValue(params[1]);
+ if (nAmount <= 0)
+ throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
// Wallet comments
CWalletTx wtx;
- if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
+ if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
wtx.mapValue["comment"] = params[2].get_str();
- if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
+ if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
wtx.mapValue["to"] = params[3].get_str();
bool fSubtractFeeFromAmount = false;
@@ -435,10 +435,10 @@ Value sendtoaddress(const Array& params, bool fHelp)
return wtx.GetHash().GetHex();
}
-Value listaddressgroupings(const Array& params, bool fHelp)
+UniValue listaddressgroupings(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp)
throw runtime_error(
@@ -465,14 +465,14 @@ Value listaddressgroupings(const Array& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- Array jsonGroupings;
+ UniValue jsonGroupings(UniValue::VARR);
map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
{
- Array jsonGrouping;
+ UniValue jsonGrouping(UniValue::VARR);
BOOST_FOREACH(CTxDestination address, grouping)
{
- Array addressInfo;
+ UniValue addressInfo(UniValue::VARR);
addressInfo.push_back(CBitcoinAddress(address).ToString());
addressInfo.push_back(ValueFromAmount(balances[address]));
{
@@ -487,10 +487,10 @@ Value listaddressgroupings(const Array& params, bool fHelp)
return jsonGroupings;
}
-Value signmessage(const Array& params, bool fHelp)
+UniValue signmessage(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 2)
throw runtime_error(
@@ -543,10 +543,10 @@ Value signmessage(const Array& params, bool fHelp)
return EncodeBase64(&vchSig[0], vchSig.size());
}
-Value getreceivedbyaddress(const Array& params, bool fHelp)
+UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -601,10 +601,10 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
}
-Value getreceivedbyaccount(const Array& params, bool fHelp)
+UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -690,10 +690,10 @@ CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminef
}
-Value getbalance(const Array& params, bool fHelp)
+UniValue getbalance(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 3)
throw runtime_error(
@@ -733,12 +733,12 @@ Value getbalance(const Array& params, bool fHelp)
if (params[0].get_str() == "*") {
// Calculate total balance a different way from GetBalance()
// (GetBalance() sums up all unspent TxOuts)
- // getbalance and getbalance '*' 0 should return the same number
+ // getbalance and "getbalance * 1 true" should return the same number
CAmount nBalance = 0;
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
- if (!wtx.IsTrusted() || wtx.GetBlocksToMaturity() > 0)
+ if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
continue;
CAmount allFee;
@@ -765,10 +765,10 @@ Value getbalance(const Array& params, bool fHelp)
return ValueFromAmount(nBalance);
}
-Value getunconfirmedbalance(const Array &params, bool fHelp)
+UniValue getunconfirmedbalance(const UniValue &params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 0)
throw runtime_error(
@@ -781,10 +781,10 @@ Value getunconfirmedbalance(const Array &params, bool fHelp)
}
-Value movecmd(const Array& params, bool fHelp)
+UniValue movecmd(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 3 || params.size() > 5)
throw runtime_error(
@@ -811,6 +811,8 @@ Value movecmd(const Array& params, bool fHelp)
string strFrom = AccountFromValue(params[0]);
string strTo = AccountFromValue(params[1]);
CAmount nAmount = AmountFromValue(params[2]);
+ if (nAmount <= 0)
+ throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
if (params.size() > 3)
// unused parameter, used to be nMinDepth, keep type-checking it though
(void)params[3].get_int();
@@ -851,10 +853,10 @@ Value movecmd(const Array& params, bool fHelp)
}
-Value sendfrom(const Array& params, bool fHelp)
+UniValue sendfrom(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 3 || params.size() > 6)
throw runtime_error(
@@ -890,15 +892,17 @@ Value sendfrom(const Array& params, bool fHelp)
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
CAmount nAmount = AmountFromValue(params[2]);
+ if (nAmount <= 0)
+ throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
int nMinDepth = 1;
if (params.size() > 3)
nMinDepth = params[3].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
- if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
+ if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty())
wtx.mapValue["comment"] = params[4].get_str();
- if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
+ if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty())
wtx.mapValue["to"] = params[5].get_str();
EnsureWalletIsUnlocked();
@@ -914,10 +918,10 @@ Value sendfrom(const Array& params, bool fHelp)
}
-Value sendmany(const Array& params, bool fHelp)
+UniValue sendmany(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 2 || params.size() > 5)
throw runtime_error(
@@ -958,17 +962,17 @@ Value sendmany(const Array& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
string strAccount = AccountFromValue(params[0]);
- Object sendTo = params[1].get_obj();
+ UniValue sendTo = params[1].get_obj();
int nMinDepth = 1;
if (params.size() > 2)
nMinDepth = params[2].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
- if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
+ if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
wtx.mapValue["comment"] = params[3].get_str();
- Array subtractFeeFromAmount;
+ UniValue subtractFeeFromAmount(UniValue::VARR);
if (params.size() > 4)
subtractFeeFromAmount = params[4].get_array();
@@ -976,24 +980,29 @@ Value sendmany(const Array& params, bool fHelp)
vector<CRecipient> vecSend;
CAmount totalAmount = 0;
- BOOST_FOREACH(const Pair& s, sendTo)
+ vector<string> keys = sendTo.getKeys();
+ BOOST_FOREACH(const string& name_, keys)
{
- CBitcoinAddress address(s.name_);
+ CBitcoinAddress address(name_);
if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_);
if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
+ throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
setAddress.insert(address);
CScript scriptPubKey = GetScriptForDestination(address.Get());
- CAmount nAmount = AmountFromValue(s.value_);
+ CAmount nAmount = AmountFromValue(sendTo[name_]);
+ if (nAmount <= 0)
+ throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
totalAmount += nAmount;
bool fSubtractFeeFromAmount = false;
- BOOST_FOREACH(const Value& addr, subtractFeeFromAmount)
- if (addr.get_str() == s.name_)
+ for (unsigned int idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
+ const UniValue& addr = subtractFeeFromAmount[idx];
+ if (addr.get_str() == name_)
fSubtractFeeFromAmount = true;
+ }
CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
vecSend.push_back(recipient);
@@ -1021,12 +1030,12 @@ Value sendmany(const Array& params, bool fHelp)
}
// Defined in rpcmisc.cpp
-extern CScript _createmultisig_redeemScript(const Array& params);
+extern CScript _createmultisig_redeemScript(const UniValue& params);
-Value addmultisigaddress(const Array& params, bool fHelp)
+UniValue addmultisigaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 2 || params.size() > 3)
{
@@ -1086,7 +1095,7 @@ struct tallyitem
}
};
-Value ListReceived(const Array& params, bool fByAccounts)
+UniValue ListReceived(const UniValue& params, bool fByAccounts)
{
// Minimum confirmations
int nMinDepth = 1;
@@ -1136,7 +1145,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
}
// Reply
- Array ret;
+ UniValue ret(UniValue::VARR);
map<string, tallyitem> mapAccountTally;
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
{
@@ -1165,14 +1174,14 @@ Value ListReceived(const Array& params, bool fByAccounts)
}
else
{
- Object obj;
+ UniValue obj(UniValue::VOBJ);
if(fIsWatchonly)
obj.push_back(Pair("involvesWatchonly", true));
obj.push_back(Pair("address", address.ToString()));
obj.push_back(Pair("account", strAccount));
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
- Array transactions;
+ UniValue transactions(UniValue::VARR);
if (it != mapTally.end())
{
BOOST_FOREACH(const uint256& item, (*it).second.txids)
@@ -1191,7 +1200,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
{
CAmount nAmount = (*it).second.nAmount;
int nConf = (*it).second.nConf;
- Object obj;
+ UniValue obj(UniValue::VOBJ);
if((*it).second.fIsWatchonly)
obj.push_back(Pair("involvesWatchonly", true));
obj.push_back(Pair("account", (*it).first));
@@ -1204,10 +1213,10 @@ Value ListReceived(const Array& params, bool fByAccounts)
return ret;
}
-Value listreceivedbyaddress(const Array& params, bool fHelp)
+UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 3)
throw runtime_error(
@@ -1241,10 +1250,10 @@ Value listreceivedbyaddress(const Array& params, bool fHelp)
return ListReceived(params, false);
}
-Value listreceivedbyaccount(const Array& params, bool fHelp)
+UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 3)
throw runtime_error(
@@ -1277,14 +1286,14 @@ Value listreceivedbyaccount(const Array& params, bool fHelp)
return ListReceived(params, true);
}
-static void MaybePushAddress(Object & entry, const CTxDestination &dest)
+static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
{
CBitcoinAddress addr;
if (addr.Set(dest))
entry.push_back(Pair("address", addr.ToString()));
}
-void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
+void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
{
CAmount nFee;
string strSentAccount;
@@ -1301,7 +1310,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
{
BOOST_FOREACH(const COutputEntry& s, listSent)
{
- Object entry;
+ UniValue entry(UniValue::VOBJ);
if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
entry.push_back(Pair("involvesWatchonly", true));
entry.push_back(Pair("account", strSentAccount));
@@ -1326,7 +1335,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
account = pwalletMain->mapAddressBook[r.destination].name;
if (fAllAccounts || (account == strAccount))
{
- Object entry;
+ UniValue entry(UniValue::VOBJ);
if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
entry.push_back(Pair("involvesWatchonly", true));
entry.push_back(Pair("account", account));
@@ -1354,13 +1363,13 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
}
}
-void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
+void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret)
{
bool fAllAccounts = (strAccount == string("*"));
if (fAllAccounts || acentry.strAccount == strAccount)
{
- Object entry;
+ UniValue entry(UniValue::VOBJ);
entry.push_back(Pair("account", acentry.strAccount));
entry.push_back(Pair("category", "move"));
entry.push_back(Pair("time", acentry.nTime));
@@ -1371,10 +1380,10 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Ar
}
}
-Value listtransactions(const Array& params, bool fHelp)
+UniValue listtransactions(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 4)
throw runtime_error(
@@ -1449,7 +1458,7 @@ Value listtransactions(const Array& params, bool fHelp)
if (nFrom < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
- Array ret;
+ UniValue ret(UniValue::VARR);
std::list<CAccountingEntry> acentries;
CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
@@ -1472,23 +1481,30 @@ Value listtransactions(const Array& params, bool fHelp)
nFrom = ret.size();
if ((nFrom + nCount) > (int)ret.size())
nCount = ret.size() - nFrom;
- Array::iterator first = ret.begin();
+
+ vector<UniValue> arrTmp = ret.getValues();
+
+ vector<UniValue>::iterator first = arrTmp.begin();
std::advance(first, nFrom);
- Array::iterator last = ret.begin();
+ vector<UniValue>::iterator last = arrTmp.begin();
std::advance(last, nFrom+nCount);
- if (last != ret.end()) ret.erase(last, ret.end());
- if (first != ret.begin()) ret.erase(ret.begin(), first);
+ if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
+ if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
- std::reverse(ret.begin(), ret.end()); // Return oldest to newest
+ std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
+
+ ret.clear();
+ ret.setArray();
+ ret.push_backV(arrTmp);
return ret;
}
-Value listaccounts(const Array& params, bool fHelp)
+UniValue listaccounts(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 2)
throw runtime_error(
@@ -1558,17 +1574,17 @@ Value listaccounts(const Array& params, bool fHelp)
BOOST_FOREACH(const CAccountingEntry& entry, acentries)
mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
- Object ret;
+ UniValue ret(UniValue::VOBJ);
BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
}
return ret;
}
-Value listsinceblock(const Array& params, bool fHelp)
+UniValue listsinceblock(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp)
throw runtime_error(
@@ -1636,7 +1652,7 @@ Value listsinceblock(const Array& params, bool fHelp)
int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
- Array transactions;
+ UniValue transactions(UniValue::VARR);
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
{
@@ -1649,17 +1665,17 @@ Value listsinceblock(const Array& params, bool fHelp)
CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
- Object ret;
+ UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("transactions", transactions));
ret.push_back(Pair("lastblock", lastblock.GetHex()));
return ret;
}
-Value gettransaction(const Array& params, bool fHelp)
+UniValue gettransaction(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -1707,7 +1723,7 @@ Value gettransaction(const Array& params, bool fHelp)
if(params[1].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
- Object entry;
+ UniValue entry(UniValue::VOBJ);
if (!pwalletMain->mapWallet.count(hash))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
const CWalletTx& wtx = pwalletMain->mapWallet[hash];
@@ -1723,7 +1739,7 @@ Value gettransaction(const Array& params, bool fHelp)
WalletTxToJSON(wtx, entry);
- Array details;
+ UniValue details(UniValue::VARR);
ListTransactions(wtx, "*", 0, false, details, filter);
entry.push_back(Pair("details", details));
@@ -1734,10 +1750,10 @@ Value gettransaction(const Array& params, bool fHelp)
}
-Value backupwallet(const Array& params, bool fHelp)
+UniValue backupwallet(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -1756,14 +1772,14 @@ Value backupwallet(const Array& params, bool fHelp)
if (!BackupWallet(*pwalletMain, strDest))
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
- return Value::null;
+ return NullUniValue;
}
-Value keypoolrefill(const Array& params, bool fHelp)
+UniValue keypoolrefill(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 1)
throw runtime_error(
@@ -1793,7 +1809,7 @@ Value keypoolrefill(const Array& params, bool fHelp)
if (pwalletMain->GetKeyPoolSize() < kpSize)
throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
- return Value::null;
+ return NullUniValue;
}
@@ -1804,10 +1820,10 @@ static void LockWallet(CWallet* pWallet)
pWallet->Lock();
}
-Value walletpassphrase(const Array& params, bool fHelp)
+UniValue walletpassphrase(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
throw runtime_error(
@@ -1860,14 +1876,14 @@ Value walletpassphrase(const Array& params, bool fHelp)
nWalletUnlockTime = GetTime() + nSleepTime;
RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
- return Value::null;
+ return NullUniValue;
}
-Value walletpassphrasechange(const Array& params, bool fHelp)
+UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
throw runtime_error(
@@ -1906,14 +1922,14 @@ Value walletpassphrasechange(const Array& params, bool fHelp)
if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
- return Value::null;
+ return NullUniValue;
}
-Value walletlock(const Array& params, bool fHelp)
+UniValue walletlock(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
throw runtime_error(
@@ -1945,14 +1961,14 @@ Value walletlock(const Array& params, bool fHelp)
nWalletUnlockTime = 0;
}
- return Value::null;
+ return NullUniValue;
}
-Value encryptwallet(const Array& params, bool fHelp)
+UniValue encryptwallet(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
throw runtime_error(
@@ -2006,10 +2022,10 @@ Value encryptwallet(const Array& params, bool fHelp)
return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
}
-Value lockunspent(const Array& params, bool fHelp)
+UniValue lockunspent(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -2050,9 +2066,9 @@ Value lockunspent(const Array& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
if (params.size() == 1)
- RPCTypeCheck(params, boost::assign::list_of(bool_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
else
- RPCTypeCheck(params, boost::assign::list_of(bool_type)(array_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
bool fUnlock = params[0].get_bool();
@@ -2062,14 +2078,14 @@ Value lockunspent(const Array& params, bool fHelp)
return true;
}
- Array outputs = params[1].get_array();
- BOOST_FOREACH(Value& output, outputs)
- {
- if (output.type() != obj_type)
+ UniValue outputs = params[1].get_array();
+ for (unsigned int idx = 0; idx < outputs.size(); idx++) {
+ const UniValue& output = outputs[idx];
+ if (!output.isObject())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
- const Object& o = output.get_obj();
+ const UniValue& o = output.get_obj();
- RPCTypeCheck(o, boost::assign::map_list_of("txid", str_type)("vout", int_type));
+ RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM));
string txid = find_value(o, "txid").get_str();
if (!IsHex(txid))
@@ -2090,10 +2106,10 @@ Value lockunspent(const Array& params, bool fHelp)
return true;
}
-Value listlockunspent(const Array& params, bool fHelp)
+UniValue listlockunspent(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 0)
throw runtime_error(
@@ -2126,10 +2142,10 @@ Value listlockunspent(const Array& params, bool fHelp)
vector<COutPoint> vOutpts;
pwalletMain->ListLockedCoins(vOutpts);
- Array ret;
+ UniValue ret(UniValue::VARR);
BOOST_FOREACH(COutPoint &outpt, vOutpts) {
- Object o;
+ UniValue o(UniValue::VOBJ);
o.push_back(Pair("txid", outpt.hash.GetHex()));
o.push_back(Pair("vout", (int)outpt.n));
@@ -2139,10 +2155,10 @@ Value listlockunspent(const Array& params, bool fHelp)
return ret;
}
-Value settxfee(const Array& params, bool fHelp)
+UniValue settxfee(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 1)
throw runtime_error(
@@ -2160,18 +2176,16 @@ Value settxfee(const Array& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
// Amount
- CAmount nAmount = 0;
- if (params[0].get_real() != 0.0)
- nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
+ CAmount nAmount = AmountFromValue(params[0]);
payTxFee = CFeeRate(nAmount, 1000);
return true;
}
-Value getwalletinfo(const Array& params, bool fHelp)
+UniValue getwalletinfo(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -2187,6 +2201,7 @@ Value getwalletinfo(const Array& params, bool fHelp)
" \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
" \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
" \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
+ " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in btc/kb\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getwalletinfo", "")
@@ -2195,7 +2210,7 @@ Value getwalletinfo(const Array& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
@@ -2205,13 +2220,14 @@ Value getwalletinfo(const Array& params, bool fHelp)
obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
if (pwalletMain->IsCrypted())
obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
+ obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
return obj;
}
-Value resendwallettransactions(const Array& params, bool fHelp)
+UniValue resendwallettransactions(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -2225,7 +2241,7 @@ Value resendwallettransactions(const Array& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
- Array result;
+ UniValue result(UniValue::VARR);
BOOST_FOREACH(const uint256& txid, txids)
{
result.push_back(txid.ToString());
@@ -2233,10 +2249,10 @@ Value resendwallettransactions(const Array& params, bool fHelp)
return result;
}
-Value listunspent(const Array& params, bool fHelp)
+UniValue listunspent(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 3)
throw runtime_error(
@@ -2274,7 +2290,7 @@ Value listunspent(const Array& params, bool fHelp)
+ HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
);
- RPCTypeCheck(params, boost::assign::list_of(int_type)(int_type)(array_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
int nMinDepth = 1;
if (params.size() > 0)
@@ -2286,8 +2302,9 @@ Value listunspent(const Array& params, bool fHelp)
set<CBitcoinAddress> setAddress;
if (params.size() > 2) {
- Array inputs = params[2].get_array();
- BOOST_FOREACH(Value& input, inputs) {
+ UniValue inputs = params[2].get_array();
+ for (unsigned int idx = 0; idx < inputs.size(); idx++) {
+ const UniValue& input = inputs[idx];
CBitcoinAddress address(input.get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+input.get_str());
@@ -2297,7 +2314,7 @@ Value listunspent(const Array& params, bool fHelp)
}
}
- Array results;
+ UniValue results(UniValue::VARR);
vector<COutput> vecOutputs;
assert(pwalletMain != NULL);
LOCK2(cs_main, pwalletMain->cs_wallet);
@@ -2317,7 +2334,7 @@ Value listunspent(const Array& params, bool fHelp)
CAmount nValue = out.tx->vout[out.i].nValue;
const CScript& pk = out.tx->vout[out.i].scriptPubKey;
- Object entry;
+ UniValue entry(UniValue::VOBJ);
entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
entry.push_back(Pair("vout", out.i));
CTxDestination address;
@@ -2343,4 +2360,58 @@ Value listunspent(const Array& params, bool fHelp)
}
return results;
-} \ No newline at end of file
+}
+
+UniValue fundrawtransaction(const UniValue& params, bool fHelp)
+{
+ if (!EnsureWalletIsAvailable(fHelp))
+ return NullUniValue;
+
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "fundrawtransaction \"hexstring\"\n"
+ "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
+ "This will not modify existing inputs, and will add one change output to the outputs.\n"
+ "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
+ "The inputs added will not be signed, use signrawtransaction for that.\n"
+ "\nArguments:\n"
+ "1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
+ "\nResult:\n"
+ "{\n"
+ " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
+ " \"fee\": n, (numeric) The fee added to the transaction\n"
+ " \"changepos\": n (numeric) The position of the added change output, or -1\n"
+ "}\n"
+ "\"hex\" \n"
+ "\nExamples:\n"
+ "\nCreate a transaction with no inputs\n"
+ + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
+ "\nAdd sufficient unsigned inputs to meet the output value\n"
+ + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
+ "\nSign the transaction\n"
+ + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
+ "\nSend the transaction\n"
+ + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
+ );
+
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
+
+ // parse hex string from parameter
+ CTransaction origTx;
+ if (!DecodeHexTx(origTx, params[0].get_str()))
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
+
+ CMutableTransaction tx(origTx);
+ CAmount nFee;
+ string strFailReason;
+ int nChangePos = -1;
+ if(!pwalletMain->FundTransaction(tx, nFee, nChangePos, strFailReason))
+ throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
+
+ UniValue result(UniValue::VOBJ);
+ result.push_back(Pair("hex", EncodeHexTx(tx)));
+ result.push_back(Pair("changepos", nChangePos));
+ result.push_back(Pair("fee", ValueFromAmount(nFee)));
+
+ return result;
+}
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 36baf930a5..eee57900b5 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -776,18 +776,6 @@ void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock)
}
}
-void CWallet::EraseFromWallet(const uint256 &hash)
-{
- if (!fFileBacked)
- return;
- {
- LOCK(cs_wallet);
- if (mapWallet.erase(hash))
- CWalletDB(strWalletFile).EraseTx(hash);
- }
- return;
-}
-
isminetype CWallet::IsMine(const CTxIn &txin) const
{
@@ -1521,7 +1509,7 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
isminetype mine = IsMine(pcoin->vout[i]);
if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
!IsLockedCoin((*it).first, i) && (pcoin->vout[i].nValue > 0 || fIncludeZeroValue) &&
- (!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i)))
+ (!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected((*it).first, i)))
vCoins.push_back(COutput(pcoin, i, nDepth, (mine & ISMINE_SPENDABLE) != ISMINE_NO));
}
}
@@ -1681,25 +1669,108 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*
AvailableCoins(vCoins, true, coinControl);
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
- if (coinControl && coinControl->HasSelected())
+ if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs)
{
BOOST_FOREACH(const COutput& out, vCoins)
{
- if(!out.fSpendable)
- continue;
+ if (!out.fSpendable)
+ continue;
nValueRet += out.tx->vout[out.i].nValue;
setCoinsRet.insert(make_pair(out.tx, out.i));
}
return (nValueRet >= nTargetValue);
}
- return (SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet) ||
- SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet) ||
- (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet)));
+ // calculate value from preset inputs and store them
+ set<pair<const CWalletTx*, uint32_t> > setPresetCoins;
+ CAmount nValueFromPresetInputs = 0;
+
+ std::vector<COutPoint> vPresetInputs;
+ if (coinControl)
+ coinControl->ListSelected(vPresetInputs);
+ BOOST_FOREACH(const COutPoint& outpoint, vPresetInputs)
+ {
+ map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash);
+ if (it != mapWallet.end())
+ {
+ const CWalletTx* pcoin = &it->second;
+ // Clearly invalid input, fail
+ if (pcoin->vout.size() <= outpoint.n)
+ return false;
+ nValueFromPresetInputs += pcoin->vout[outpoint.n].nValue;
+ setPresetCoins.insert(make_pair(pcoin, outpoint.n));
+ } else
+ return false; // TODO: Allow non-wallet inputs
+ }
+
+ // remove preset inputs from vCoins
+ for (vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();)
+ {
+ if (setPresetCoins.count(make_pair(it->tx, it->i)))
+ it = vCoins.erase(it);
+ else
+ ++it;
+ }
+
+ bool res = nTargetValue <= nValueFromPresetInputs ||
+ SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, vCoins, setCoinsRet, nValueRet) ||
+ SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, vCoins, setCoinsRet, nValueRet) ||
+ (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, vCoins, setCoinsRet, nValueRet));
+
+ // because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
+ setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end());
+
+ // add preset inputs to the total value selected
+ nValueRet += nValueFromPresetInputs;
+
+ return res;
}
-bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend,
- CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl)
+bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nChangePosRet, std::string& strFailReason)
+{
+ vector<CRecipient> vecSend;
+
+ // Turn the txout set into a CRecipient vector
+ BOOST_FOREACH(const CTxOut& txOut, tx.vout)
+ {
+ CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, false};
+ vecSend.push_back(recipient);
+ }
+
+ CCoinControl coinControl;
+ coinControl.fAllowOtherInputs = true;
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ coinControl.Select(txin.prevout);
+
+ CReserveKey reservekey(this);
+ CWalletTx wtx;
+ if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosRet, strFailReason, &coinControl, false))
+ return false;
+
+ if (nChangePosRet != -1)
+ tx.vout.insert(tx.vout.begin() + nChangePosRet, wtx.vout[nChangePosRet]);
+
+ // Add new txins (keeping original txin scriptSig/order)
+ BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ {
+ bool found = false;
+ BOOST_FOREACH(const CTxIn& origTxIn, tx.vin)
+ {
+ if (txin.prevout.hash == origTxIn.prevout.hash && txin.prevout.n == origTxIn.prevout.n)
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ tx.vin.push_back(txin);
+ }
+
+ return true;
+}
+
+bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
+ int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl, bool sign)
{
CAmount nValue = 0;
unsigned int nSubtractFeeFromAmount = 0;
@@ -1902,23 +1973,43 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend,
// Sign
int nIn = 0;
+ CTransaction txNewConst(txNew);
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
- if (!SignSignature(*this, *coin.first, txNew, nIn++))
+ {
+ bool signSuccess;
+ const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey;
+ CScript& scriptSigRes = txNew.vin[nIn].scriptSig;
+ if (sign)
+ signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, SIGHASH_ALL), scriptPubKey, scriptSigRes);
+ else
+ signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, scriptSigRes);
+
+ if (!signSuccess)
{
strFailReason = _("Signing transaction failed");
return false;
}
+ nIn++;
+ }
+
+ unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
+
+ // Remove scriptSigs if we used dummy signatures for fee calculation
+ if (!sign) {
+ BOOST_FOREACH (CTxIn& vin, txNew.vin)
+ vin.scriptSig = CScript();
+ }
// Embed the constructed transaction data in wtxNew.
*static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew);
// Limit size
- unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION);
if (nBytes >= MAX_STANDARD_TX_SIZE)
{
strFailReason = _("Transaction too large");
return false;
}
+
dPriority = wtxNew.ComputePriority(dPriority, nBytes);
// Can we complete this as a free transaction?
@@ -2414,7 +2505,7 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
return ret;
}
-set<CTxDestination> CWallet::GetAccountAddresses(string strAccount) const
+std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const
{
LOCK(cs_wallet);
set<CTxDestination> result;
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index b0da92cfd1..b6a8e8671f 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -496,7 +496,7 @@ public:
SetNull();
}
- CWallet(std::string strWalletFileIn)
+ CWallet(const std::string& strWalletFileIn)
{
SetNull();
@@ -615,7 +615,6 @@ public:
bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb);
void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
- void EraseFromWallet(const uint256 &hash);
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime);
@@ -626,8 +625,9 @@ public:
CAmount GetWatchOnlyBalance() const;
CAmount GetUnconfirmedWatchOnlyBalance() const;
CAmount GetImmatureWatchOnlyBalance() const;
- bool CreateTransaction(const std::vector<CRecipient>& vecSend,
- CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet, std::string& strFailReason, const CCoinControl *coinControl = NULL);
+ bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosRet, std::string& strFailReason);
+ bool CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet,
+ std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true);
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
static CFeeRate minTxFee;
@@ -645,7 +645,7 @@ public:
std::set< std::set<CTxDestination> > GetAddressGroupings();
std::map<CTxDestination, CAmount> GetAddressBalances();
- std::set<CTxDestination> GetAccountAddresses(std::string strAccount) const;
+ std::set<CTxDestination> GetAccountAddresses(const std::string& strAccount) const;
isminetype IsMine(const CTxIn& txin) const;
CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const;