aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.bench.include6
-rw-r--r--src/addrman.cpp8
-rw-r--r--src/addrman.h3
-rw-r--r--src/bench/ccoins_caching.cpp87
-rw-r--r--src/bench/coin_selection.cpp62
-rw-r--r--src/bench/mempool_eviction.cpp115
-rw-r--r--src/bench/verify_script.cpp103
-rw-r--r--src/bitcoin-cli.cpp2
-rw-r--r--src/bitcoin-tx.cpp2
-rw-r--r--src/chain.h2
-rw-r--r--src/chainparams.cpp20
-rw-r--r--src/chainparams.h3
-rw-r--r--src/consensus/params.h2
-rw-r--r--src/httprpc.cpp16
-rw-r--r--src/init.cpp7
-rw-r--r--src/main.cpp211
-rw-r--r--src/main.h83
-rw-r--r--src/miner.cpp7
-rw-r--r--src/miner.h2
-rw-r--r--src/net.cpp20
-rw-r--r--src/net.h6
-rw-r--r--src/netbase.cpp4
-rw-r--r--src/policy/fees.cpp2
-rw-r--r--src/policy/fees.h2
-rw-r--r--src/policy/policy.cpp54
-rw-r--r--src/policy/policy.h17
-rw-r--r--src/qt/forms/debugwindow.ui27
-rw-r--r--src/qt/forms/overviewpage.ui5
-rw-r--r--src/qt/guiutil.cpp2
-rw-r--r--src/qt/peertablemodel.cpp6
-rw-r--r--src/qt/receivecoinsdialog.cpp39
-rw-r--r--src/qt/receivecoinsdialog.h2
-rw-r--r--src/qt/rpcconsole.cpp6
-rw-r--r--src/qt/signverifymessagedialog.cpp2
-rw-r--r--src/qt/splashscreen.cpp12
-rw-r--r--src/qt/splashscreen.h5
-rw-r--r--src/qt/walletmodel.cpp5
-rw-r--r--src/qt/walletmodel.h1
-rw-r--r--src/random.cpp11
-rw-r--r--src/random.h35
-rw-r--r--src/rest.cpp7
-rw-r--r--src/rpc/blockchain.cpp200
-rw-r--r--src/rpc/mining.cpp172
-rw-r--r--src/rpc/misc.cpp44
-rw-r--r--src/rpc/net.cpp76
-rw-r--r--src/rpc/protocol.cpp4
-rw-r--r--src/rpc/protocol.h2
-rw-r--r--src/rpc/rawtransaction.cpp105
-rw-r--r--src/rpc/server.cpp29
-rw-r--r--src/rpc/server.h14
-rw-r--r--src/script/interpreter.cpp32
-rw-r--r--src/script/interpreter.h6
-rw-r--r--src/script/ismine.cpp62
-rw-r--r--src/script/ismine.h11
-rw-r--r--src/script/script_error.cpp2
-rw-r--r--src/script/script_error.h1
-rw-r--r--src/script/sign.cpp6
-rw-r--r--src/test/addrman_tests.cpp2
-rw-r--r--src/test/coins_tests.cpp2
-rw-r--r--src/test/crypto_tests.cpp2
-rw-r--r--src/test/data/script_tests.json368
-rw-r--r--src/test/data/tx_invalid.json26
-rw-r--r--src/test/data/tx_valid.json23
-rw-r--r--src/test/merkle_tests.cpp2
-rw-r--r--src/test/miner_tests.cpp17
-rw-r--r--src/test/net_tests.cpp2
-rw-r--r--src/test/pmt_tests.cpp2
-rw-r--r--src/test/prevector_tests.cpp14
-rw-r--r--src/test/rpc_tests.cpp7
-rw-r--r--src/test/scheduler_tests.cpp4
-rw-r--r--src/test/script_tests.cpp94
-rw-r--r--src/test/sighash_tests.cpp2
-rw-r--r--src/test/skiplist_tests.cpp2
-rw-r--r--src/test/test_bitcoin.cpp8
-rw-r--r--src/test/test_random.h23
-rw-r--r--src/test/transaction_tests.cpp36
-rw-r--r--src/test/util_tests.cpp2
-rw-r--r--src/test/versionbits_tests.cpp106
-rw-r--r--src/txmempool.cpp2
-rw-r--r--src/txmempool.h1
-rw-r--r--src/validationinterface.cpp8
-rw-r--r--src/validationinterface.h8
-rw-r--r--src/versionbits.cpp35
-rw-r--r--src/versionbits.h4
-rw-r--r--src/wallet/rpcdump.cpp100
-rw-r--r--src/wallet/rpcwallet.cpp503
-rw-r--r--src/wallet/test/crypto_tests.cpp2
-rw-r--r--src/wallet/wallet.cpp13
-rw-r--r--src/wallet/wallet.h2
-rw-r--r--src/zmq/zmqnotificationinterface.cpp7
-rw-r--r--src/zmq/zmqnotificationinterface.h2
91 files changed, 2264 insertions, 944 deletions
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 8c024a8c4a..c83432e91a 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -14,6 +14,9 @@ bench_bench_bitcoin_SOURCES = \
bench/Examples.cpp \
bench/rollingbloom.cpp \
bench/crypto_hash.cpp \
+ bench/ccoins_caching.cpp \
+ bench/mempool_eviction.cpp \
+ bench/verify_script.cpp \
bench/base58.cpp
bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/
@@ -34,7 +37,8 @@ bench_bench_bitcoin_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
endif
if ENABLE_WALLET
-bench_bench_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
+bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp
+bench_bench_bitcoin_LDADD += $(LIBBITCOIN_WALLET) $(LIBBITCOIN_CRYPTO)
endif
bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
diff --git a/src/addrman.cpp b/src/addrman.cpp
index bfb8e94575..2016523212 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -358,8 +358,8 @@ CAddrInfo CAddrMan::Select_(bool newOnly)
int nKBucket = RandomInt(ADDRMAN_TRIED_BUCKET_COUNT);
int nKBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE);
while (vvTried[nKBucket][nKBucketPos] == -1) {
- nKBucket = (nKBucket + insecure_rand()) % ADDRMAN_TRIED_BUCKET_COUNT;
- nKBucketPos = (nKBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE;
+ nKBucket = (nKBucket + insecure_rand.rand32()) % ADDRMAN_TRIED_BUCKET_COUNT;
+ nKBucketPos = (nKBucketPos + insecure_rand.rand32()) % ADDRMAN_BUCKET_SIZE;
}
int nId = vvTried[nKBucket][nKBucketPos];
assert(mapInfo.count(nId) == 1);
@@ -375,8 +375,8 @@ CAddrInfo CAddrMan::Select_(bool newOnly)
int nUBucket = RandomInt(ADDRMAN_NEW_BUCKET_COUNT);
int nUBucketPos = RandomInt(ADDRMAN_BUCKET_SIZE);
while (vvNew[nUBucket][nUBucketPos] == -1) {
- nUBucket = (nUBucket + insecure_rand()) % ADDRMAN_NEW_BUCKET_COUNT;
- nUBucketPos = (nUBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE;
+ nUBucket = (nUBucket + insecure_rand.rand32()) % ADDRMAN_NEW_BUCKET_COUNT;
+ nUBucketPos = (nUBucketPos + insecure_rand.rand32()) % ADDRMAN_BUCKET_SIZE;
}
int nId = vvNew[nUBucket][nUBucketPos];
assert(mapInfo.count(nId) == 1);
diff --git a/src/addrman.h b/src/addrman.h
index 9bab39049d..e9e137c978 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -211,6 +211,9 @@ protected:
//! secret key to randomize bucket select with
uint256 nKey;
+ //! Source of random numbers for randomization in inner loops
+ FastRandomContext insecure_rand;
+
//! Find an entry.
CAddrInfo* Find(const CNetAddr& addr, int *pnId = NULL);
diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp
new file mode 100644
index 0000000000..1e8e3d462f
--- /dev/null
+++ b/src/bench/ccoins_caching.cpp
@@ -0,0 +1,87 @@
+// Copyright (c) 2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "bench.h"
+#include "coins.h"
+#include "policy/policy.h"
+#include "wallet/crypter.h"
+
+#include <vector>
+
+// FIXME: Dedup with SetupDummyInputs in test/transaction_tests.cpp.
+//
+// Helper: create two dummy transactions, each with
+// two outputs. The first has 11 and 50 CENT outputs
+// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs
+// paid to a TX_PUBKEYHASH.
+//
+static std::vector<CMutableTransaction>
+SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
+{
+ std::vector<CMutableTransaction> dummyTransactions;
+ dummyTransactions.resize(2);
+
+ // Add some keys to the keystore:
+ CKey key[4];
+ for (int i = 0; i < 4; i++) {
+ key[i].MakeNewKey(i % 2);
+ keystoreRet.AddKey(key[i]);
+ }
+
+ // Create some dummy input transactions
+ dummyTransactions[0].vout.resize(2);
+ dummyTransactions[0].vout[0].nValue = 11 * CENT;
+ dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
+ dummyTransactions[0].vout[1].nValue = 50 * CENT;
+ dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;
+ coinsRet.ModifyCoins(dummyTransactions[0].GetHash())->FromTx(dummyTransactions[0], 0);
+
+ dummyTransactions[1].vout.resize(2);
+ dummyTransactions[1].vout[0].nValue = 21 * CENT;
+ dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());
+ dummyTransactions[1].vout[1].nValue = 22 * CENT;
+ dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());
+ coinsRet.ModifyCoins(dummyTransactions[1].GetHash())->FromTx(dummyTransactions[1], 0);
+
+ return dummyTransactions;
+}
+
+// Microbenchmark for simple accesses to a CCoinsViewCache database. Note from
+// laanwj, "replicating the actual usage patterns of the client is hard though,
+// many times micro-benchmarks of the database showed completely different
+// characteristics than e.g. reindex timings. But that's not a requirement of
+// every benchmark."
+// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)
+static void CCoinsCaching(benchmark::State& state)
+{
+ CBasicKeyStore keystore;
+ CCoinsView coinsDummy;
+ CCoinsViewCache coins(&coinsDummy);
+ std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
+
+ CMutableTransaction t1;
+ t1.vin.resize(3);
+ t1.vin[0].prevout.hash = dummyTransactions[0].GetHash();
+ t1.vin[0].prevout.n = 1;
+ t1.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
+ t1.vin[1].prevout.hash = dummyTransactions[1].GetHash();
+ t1.vin[1].prevout.n = 0;
+ t1.vin[1].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
+ t1.vin[2].prevout.hash = dummyTransactions[1].GetHash();
+ t1.vin[2].prevout.n = 1;
+ t1.vin[2].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
+ t1.vout.resize(2);
+ t1.vout[0].nValue = 90 * CENT;
+ t1.vout[0].scriptPubKey << OP_1;
+
+ // Benchmark.
+ while (state.KeepRunning()) {
+ bool success = AreInputsStandard(t1, coins);
+ assert(success);
+ CAmount value = coins.GetValueIn(t1);
+ assert(value == (50 + 21 + 22) * CENT);
+ }
+}
+
+BENCHMARK(CCoinsCaching);
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
new file mode 100644
index 0000000000..7091ee3e11
--- /dev/null
+++ b/src/bench/coin_selection.cpp
@@ -0,0 +1,62 @@
+// Copyright (c) 2012-2015 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "bench.h"
+#include "wallet/wallet.h"
+
+#include <boost/foreach.hpp>
+#include <set>
+
+using namespace std;
+
+static void addCoin(const CAmount& nValue, const CWallet& wallet, vector<COutput>& vCoins)
+{
+ int nInput = 0;
+
+ static int nextLockTime = 0;
+ CMutableTransaction tx;
+ tx.nLockTime = nextLockTime++; // so all transactions get different hashes
+ tx.vout.resize(nInput + 1);
+ tx.vout[nInput].nValue = nValue;
+ CWalletTx* wtx = new CWalletTx(&wallet, tx);
+
+ int nAge = 6 * 24;
+ COutput output(wtx, nInput, nAge, true, true);
+ vCoins.push_back(output);
+}
+
+// Simple benchmark for wallet coin selection. Note that it maybe be necessary
+// to build up more complicated scenarios in order to get meaningful
+// measurements of performance. From laanwj, "Wallet coin selection is probably
+// the hardest, as you need a wider selection of scenarios, just testing the
+// same one over and over isn't too useful. Generating random isn't useful
+// either for measurements."
+// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)
+static void CoinSelection(benchmark::State& state)
+{
+ const CWallet wallet;
+ vector<COutput> vCoins;
+ LOCK(wallet.cs_wallet);
+
+ while (state.KeepRunning()) {
+ // Empty wallet.
+ BOOST_FOREACH (COutput output, vCoins)
+ delete output.tx;
+ vCoins.clear();
+
+ // Add coins.
+ for (int i = 0; i < 1000; i++)
+ addCoin(1000 * COIN, wallet, vCoins);
+ addCoin(3 * COIN, wallet, vCoins);
+
+ set<pair<const CWalletTx*, unsigned int> > setCoinsRet;
+ CAmount nValueRet;
+ bool success = wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet);
+ assert(success);
+ assert(nValueRet == 1003 * COIN);
+ assert(setCoinsRet.size() == 2);
+ }
+}
+
+BENCHMARK(CoinSelection);
diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp
new file mode 100644
index 0000000000..0ae69c75fc
--- /dev/null
+++ b/src/bench/mempool_eviction.cpp
@@ -0,0 +1,115 @@
+// Copyright (c) 2011-2015 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "bench.h"
+#include "policy/policy.h"
+#include "txmempool.h"
+
+#include <list>
+#include <vector>
+
+static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool)
+{
+ int64_t nTime = 0;
+ double dPriority = 10.0;
+ unsigned int nHeight = 1;
+ bool spendsCoinbase = false;
+ unsigned int sigOpCost = 4;
+ LockPoints lp;
+ pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(
+ tx, nFee, nTime, dPriority, nHeight, pool.HasNoInputsOf(tx),
+ tx.GetValueOut(), spendsCoinbase, sigOpCost, lp));
+}
+
+// Right now this is only testing eviction performance in an extremely small
+// mempool. Code needs to be written to generate a much wider variety of
+// unique transactions for a more meaningful performance measurement.
+static void MempoolEviction(benchmark::State& state)
+{
+ CMutableTransaction tx1 = CMutableTransaction();
+ tx1.vin.resize(1);
+ tx1.vin[0].scriptSig = CScript() << OP_1;
+ tx1.vout.resize(1);
+ tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
+ tx1.vout[0].nValue = 10 * COIN;
+
+ CMutableTransaction tx2 = CMutableTransaction();
+ tx2.vin.resize(1);
+ tx2.vin[0].scriptSig = CScript() << OP_2;
+ tx2.vout.resize(1);
+ tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL;
+ tx2.vout[0].nValue = 10 * COIN;
+
+ CMutableTransaction tx3 = CMutableTransaction();
+ tx3.vin.resize(1);
+ tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0);
+ tx3.vin[0].scriptSig = CScript() << OP_2;
+ tx3.vout.resize(1);
+ tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL;
+ tx3.vout[0].nValue = 10 * COIN;
+
+ CMutableTransaction tx4 = CMutableTransaction();
+ tx4.vin.resize(2);
+ tx4.vin[0].prevout.SetNull();
+ tx4.vin[0].scriptSig = CScript() << OP_4;
+ tx4.vin[1].prevout.SetNull();
+ tx4.vin[1].scriptSig = CScript() << OP_4;
+ tx4.vout.resize(2);
+ tx4.vout[0].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
+ tx4.vout[0].nValue = 10 * COIN;
+ tx4.vout[1].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
+ tx4.vout[1].nValue = 10 * COIN;
+
+ CMutableTransaction tx5 = CMutableTransaction();
+ tx5.vin.resize(2);
+ tx5.vin[0].prevout = COutPoint(tx4.GetHash(), 0);
+ tx5.vin[0].scriptSig = CScript() << OP_4;
+ tx5.vin[1].prevout.SetNull();
+ tx5.vin[1].scriptSig = CScript() << OP_5;
+ tx5.vout.resize(2);
+ tx5.vout[0].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
+ tx5.vout[0].nValue = 10 * COIN;
+ tx5.vout[1].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
+ tx5.vout[1].nValue = 10 * COIN;
+
+ CMutableTransaction tx6 = CMutableTransaction();
+ tx6.vin.resize(2);
+ tx6.vin[0].prevout = COutPoint(tx4.GetHash(), 1);
+ tx6.vin[0].scriptSig = CScript() << OP_4;
+ tx6.vin[1].prevout.SetNull();
+ tx6.vin[1].scriptSig = CScript() << OP_6;
+ tx6.vout.resize(2);
+ tx6.vout[0].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
+ tx6.vout[0].nValue = 10 * COIN;
+ tx6.vout[1].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
+ tx6.vout[1].nValue = 10 * COIN;
+
+ CMutableTransaction tx7 = CMutableTransaction();
+ tx7.vin.resize(2);
+ tx7.vin[0].prevout = COutPoint(tx5.GetHash(), 0);
+ tx7.vin[0].scriptSig = CScript() << OP_5;
+ tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0);
+ tx7.vin[1].scriptSig = CScript() << OP_6;
+ tx7.vout.resize(2);
+ tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
+ tx7.vout[0].nValue = 10 * COIN;
+ tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
+ tx7.vout[1].nValue = 10 * COIN;
+
+ CTxMemPool pool(CFeeRate(1000));
+
+ while (state.KeepRunning()) {
+ AddTx(tx1, 10000LL, pool);
+ AddTx(tx2, 5000LL, pool);
+ AddTx(tx3, 20000LL, pool);
+ AddTx(tx4, 7000LL, pool);
+ AddTx(tx5, 1000LL, pool);
+ AddTx(tx6, 1100LL, pool);
+ AddTx(tx7, 9000LL, pool);
+ pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4);
+ pool.TrimToSize(GetVirtualTransactionSize(tx1));
+ }
+}
+
+BENCHMARK(MempoolEviction);
diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
new file mode 100644
index 0000000000..dc3940cdbd
--- /dev/null
+++ b/src/bench/verify_script.cpp
@@ -0,0 +1,103 @@
+// Copyright (c) 2016 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "bench.h"
+#include "key.h"
+#if defined(HAVE_CONSENSUS_LIB)
+#include "script/bitcoinconsensus.h"
+#endif
+#include "script/script.h"
+#include "script/sign.h"
+#include "streams.h"
+
+// FIXME: Dedup with BuildCreditingTransaction in test/script_tests.cpp.
+static CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey)
+{
+ CMutableTransaction txCredit;
+ txCredit.nVersion = 1;
+ txCredit.nLockTime = 0;
+ txCredit.vin.resize(1);
+ txCredit.vout.resize(1);
+ txCredit.vin[0].prevout.SetNull();
+ txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0);
+ txCredit.vin[0].nSequence = CTxIn::SEQUENCE_FINAL;
+ txCredit.vout[0].scriptPubKey = scriptPubKey;
+ txCredit.vout[0].nValue = 1;
+
+ return txCredit;
+}
+
+// FIXME: Dedup with BuildSpendingTransaction in test/script_tests.cpp.
+static CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMutableTransaction& txCredit)
+{
+ CMutableTransaction txSpend;
+ txSpend.nVersion = 1;
+ txSpend.nLockTime = 0;
+ txSpend.vin.resize(1);
+ txSpend.vout.resize(1);
+ txSpend.wit.vtxinwit.resize(1);
+ txSpend.vin[0].prevout.hash = txCredit.GetHash();
+ txSpend.vin[0].prevout.n = 0;
+ txSpend.vin[0].scriptSig = scriptSig;
+ txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL;
+ txSpend.vout[0].scriptPubKey = CScript();
+ txSpend.vout[0].nValue = txCredit.vout[0].nValue;
+
+ return txSpend;
+}
+
+// Microbenchmark for verification of a basic P2WPKH script. Can be easily
+// modified to measure performance of other types of scripts.
+static void VerifyScriptBench(benchmark::State& state)
+{
+ const int flags = SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH;
+ const int witnessversion = 0;
+
+ // Keypair.
+ CKey key;
+ const unsigned char vchKey[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+ key.Set(vchKey, vchKey + 32, false);
+ CPubKey pubkey = key.GetPubKey();
+ uint160 pubkeyHash;
+ CHash160().Write(pubkey.begin(), pubkey.size()).Finalize(pubkeyHash.begin());
+
+ // Script.
+ CScript scriptPubKey = CScript() << witnessversion << ToByteVector(pubkeyHash);
+ CScript scriptSig;
+ CScript witScriptPubkey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkeyHash) << OP_EQUALVERIFY << OP_CHECKSIG;
+ CTransaction txCredit = BuildCreditingTransaction(scriptPubKey);
+ CMutableTransaction txSpend = BuildSpendingTransaction(scriptSig, txCredit);
+ CScriptWitness& witness = txSpend.wit.vtxinwit[0].scriptWitness;
+ witness.stack.emplace_back();
+ key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SIGVERSION_WITNESS_V0), witness.stack.back(), 0);
+ witness.stack.back().push_back(static_cast<unsigned char>(SIGHASH_ALL));
+ witness.stack.push_back(ToByteVector(pubkey));
+
+ // Benchmark.
+ while (state.KeepRunning()) {
+ ScriptError err;
+ bool success = VerifyScript(
+ txSpend.vin[0].scriptSig,
+ txCredit.vout[0].scriptPubKey,
+ &txSpend.wit.vtxinwit[0].scriptWitness,
+ flags,
+ MutableTransactionSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue),
+ &err);
+ assert(err == SCRIPT_ERR_OK);
+ assert(success);
+
+#if defined(HAVE_CONSENSUS_LIB)
+ CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
+ stream << txSpend;
+ int csuccess = bitcoinconsensus_verify_script_with_amount(
+ begin_ptr(txCredit.vout[0].scriptPubKey),
+ txCredit.vout[0].scriptPubKey.size(),
+ txCredit.vout[0].nValue,
+ (const unsigned char*)&stream[0], stream.size(), 0, flags, nullptr);
+ assert(csuccess == 1);
+#endif
+ }
+}
+
+BENCHMARK(VerifyScriptBench);
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 9d4c4e53bd..2d66448d80 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -223,7 +223,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());
// Attach request data
- std::string strRequest = JSONRPCRequest(strMethod, params, 1);
+ std::string strRequest = JSONRPCRequestObj(strMethod, params, 1).write() + "\n";
struct evbuffer * output_buffer = evhttp_request_get_output_buffer(req);
assert(output_buffer);
evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index cb863bda19..e09afd632e 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -164,7 +164,7 @@ static void RegisterLoad(const string& strInput)
static void MutateTxVersion(CMutableTransaction& tx, const string& cmdVal)
{
int64_t newVersion = atoi64(cmdVal);
- if (newVersion < 1 || newVersion > CTransaction::CURRENT_VERSION)
+ if (newVersion < 1 || newVersion > CTransaction::MAX_STANDARD_VERSION)
throw runtime_error("Invalid TX version requested");
tx.nVersion = (int) newVersion;
diff --git a/src/chain.h b/src/chain.h
index 6588e8f57d..e2f8c56522 100644
--- a/src/chain.h
+++ b/src/chain.h
@@ -200,7 +200,7 @@ public:
unsigned int nNonce;
//! (memory only) Sequential id assigned to distinguish order in which blocks are received.
- uint32_t nSequenceId;
+ int32_t nSequenceId;
void SetNull()
{
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index e6be1b5d5b..5850016ae2 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -91,10 +91,10 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1462060800; // May 1st, 2016
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017
- // Deployment of SegWit (BIP141 and BIP143)
+ // Deployment of SegWit (BIP141, BIP143, and BIP147)
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 0;
- consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 0; // Never / undefined
+ consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1479168000; // November 15th, 2016.
+ consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1510704000; // November 15th, 2017.
/**
* The message start string is designed to be unlikely to occur in normal data.
@@ -113,12 +113,13 @@ public:
assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
- vSeeds.push_back(CDNSSeedData("bitcoin.sipa.be", "seed.bitcoin.sipa.be", true)); // Pieter Wuille
- vSeeds.push_back(CDNSSeedData("bluematt.me", "dnsseed.bluematt.me")); // Matt Corallo
+ // Note that of those with the service bits flag, most only support a subset of possible options
+ vSeeds.push_back(CDNSSeedData("bitcoin.sipa.be", "seed.bitcoin.sipa.be", true)); // Pieter Wuille, only supports x1, x5, x9, and xd
+ vSeeds.push_back(CDNSSeedData("bluematt.me", "dnsseed.bluematt.me", true)); // Matt Corallo, only supports x9
vSeeds.push_back(CDNSSeedData("dashjr.org", "dnsseed.bitcoin.dashjr.org")); // Luke Dashjr
- vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com")); // Christian Decker
+ vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com", true)); // Christian Decker, supports x1 - xf
vSeeds.push_back(CDNSSeedData("xf2.org", "bitseed.xf2.org")); // Jeff Garzik
- vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch", true)); // Jonas Schnelli
+ vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch", true)); // Jonas Schnelli, only supports x1, x5, x9, and xd
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
@@ -132,7 +133,6 @@ public:
fDefaultConsistencyChecks = false;
fRequireStandard = true;
fMineBlocksOnDemand = false;
- fTestnetToBeDeprecatedFieldRPC = false;
checkpointData = (CCheckpointData) {
boost::assign::map_list_of
@@ -186,7 +186,7 @@ public:
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nStartTime = 1456790400; // March 1st, 2016
consensus.vDeployments[Consensus::DEPLOYMENT_CSV].nTimeout = 1493596800; // May 1st, 2017
- // Deployment of SegWit (BIP141 and BIP143)
+ // Deployment of SegWit (BIP141, BIP143, and BIP147)
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].bit = 1;
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nStartTime = 1462060800; // May 1st 2016
consensus.vDeployments[Consensus::DEPLOYMENT_SEGWIT].nTimeout = 1493596800; // May 1st 2017
@@ -223,7 +223,6 @@ public:
fDefaultConsistencyChecks = false;
fRequireStandard = false;
fMineBlocksOnDemand = false;
- fTestnetToBeDeprecatedFieldRPC = true;
checkpointData = (CCheckpointData) {
boost::assign::map_list_of
@@ -285,7 +284,6 @@ public:
fDefaultConsistencyChecks = true;
fRequireStandard = false;
fMineBlocksOnDemand = true;
- fTestnetToBeDeprecatedFieldRPC = false;
checkpointData = (CCheckpointData){
boost::assign::map_list_of
diff --git a/src/chainparams.h b/src/chainparams.h
index 0c3820b7c6..633fbd5120 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -67,8 +67,6 @@ public:
uint64_t PruneAfterHeight() const { return nPruneAfterHeight; }
/** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */
bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; }
- /** In the future use NetworkIDString() for RPC fields */
- bool TestnetToBeDeprecatedFieldRPC() const { return fTestnetToBeDeprecatedFieldRPC; }
/** Return the BIP70 network string (main, test or regtest) */
std::string NetworkIDString() const { return strNetworkID; }
const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }
@@ -91,7 +89,6 @@ protected:
bool fDefaultConsistencyChecks;
bool fRequireStandard;
bool fMineBlocksOnDemand;
- bool fTestnetToBeDeprecatedFieldRPC;
CCheckpointData checkpointData;
};
diff --git a/src/consensus/params.h b/src/consensus/params.h
index 5b2f49184f..0e73cace83 100644
--- a/src/consensus/params.h
+++ b/src/consensus/params.h
@@ -16,7 +16,7 @@ enum DeploymentPos
{
DEPLOYMENT_TESTDUMMY,
DEPLOYMENT_CSV, // Deployment of BIP68, BIP112, and BIP113.
- DEPLOYMENT_SEGWIT, // Deployment of BIP141 and BIP143
+ DEPLOYMENT_SEGWIT, // Deployment of BIP141, BIP143, and BIP147.
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp
MAX_VERSION_BITS_DEPLOYMENTS
};
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 6a6c5276cc..e35acb6cd9 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -127,7 +127,7 @@ static bool multiUserAuthorized(std::string strUserPass)
return false;
}
-static bool RPCAuthorized(const std::string& strAuth)
+static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUsernameOut)
{
if (strRPCUserColonPass.empty()) // Belt-and-suspenders measure if InitRPCAuthentication was not called
return false;
@@ -136,7 +136,10 @@ static bool RPCAuthorized(const std::string& strAuth)
std::string strUserPass64 = strAuth.substr(6);
boost::trim(strUserPass64);
std::string strUserPass = DecodeBase64(strUserPass64);
-
+
+ if (strUserPass.find(":") != std::string::npos)
+ strAuthUsernameOut = strUserPass.substr(0, strUserPass.find(":"));
+
//Check if authorized under single-user field
if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) {
return true;
@@ -159,7 +162,8 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
return false;
}
- if (!RPCAuthorized(authHeader.second)) {
+ JSONRPCRequest jreq;
+ if (!RPCAuthorized(authHeader.second, jreq.authUser)) {
LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", req->GetPeer().ToString());
/* Deter brute-forcing
@@ -172,19 +176,21 @@ static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
return false;
}
- JSONRequest jreq;
try {
// Parse request
UniValue valRequest;
if (!valRequest.read(req->ReadBody()))
throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
+ // Set the URI
+ jreq.URI = req->GetURI();
+
std::string strReply;
// singleton request
if (valRequest.isObject()) {
jreq.parse(valRequest);
- UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);
+ UniValue result = tableRPC.execute(jreq);
// Send reply
strReply = JSONRPCReply(result, NullUniValue, jreq.id);
diff --git a/src/init.cpp b/src/init.cpp
index 057d8eefee..d3efc9f978 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -72,6 +72,7 @@ static const bool DEFAULT_DISABLE_SAFEMODE = false;
static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
std::unique_ptr<CConnman> g_connman;
+std::unique_ptr<PeerLogicValidation> peerLogic;
#if ENABLE_ZMQ
static CZMQNotificationInterface* pzmqNotificationInterface = NULL;
@@ -200,6 +201,8 @@ void Shutdown()
pwalletMain->Flush(false);
#endif
MapPort(false);
+ UnregisterValidationInterface(peerLogic.get());
+ peerLogic.reset();
g_connman.reset();
StopTorControl();
@@ -423,7 +426,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT));
strUsage += HelpMessageOpt("-bip9params=deployment:start:end", "Use given start/end times for specified BIP9 deployment (regtest-only)");
}
- string debugCategories = "addrman, alert, bench, coindb, db, http, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq"; // Don't translate these and qt below
+ string debugCategories = "addrman, alert, bench, cmpctblock, coindb, db, http, libevent, lock, mempool, mempoolrej, net, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq"; // Don't translate these and qt below
if (mode == HMM_BITCOIN_QT)
debugCategories += ", qt";
strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " +
@@ -1102,6 +1105,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
g_connman = std::unique_ptr<CConnman>(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max())));
CConnman& connman = *g_connman;
+ peerLogic.reset(new PeerLogicValidation(&connman));
+ RegisterValidationInterface(peerLogic.get());
RegisterNodeSignals(GetNodeSignals());
// sanitize comments per BIP-0014, format user agent and check total size
diff --git a/src/main.cpp b/src/main.cpp
index f3b0e3c22e..50158b4687 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -169,7 +169,11 @@ namespace {
*/
CCriticalSection cs_nBlockSequenceId;
/** Blocks loaded from disk are assigned id 0, so start the counter at 1. */
- uint32_t nBlockSequenceId = 1;
+ int32_t nBlockSequenceId = 1;
+ /** Decreasing counter (used by subsequent preciousblock calls). */
+ int32_t nBlockReverseSequenceId = -1;
+ /** chainwork for the last block that preciousblock has been applied to. */
+ arith_uint256 nLastPreciousChainwork = 0;
/**
* Sources of received blocks, saved to be able to send them reject
@@ -485,9 +489,13 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pf
return;
}
if (nodestate->fProvidesHeaderAndIDs) {
- BOOST_FOREACH(const NodeId nodeid, lNodesAnnouncingHeaderAndIDs)
- if (nodeid == pfrom->GetId())
+ for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin(); it != lNodesAnnouncingHeaderAndIDs.end(); it++) {
+ if (*it == pfrom->GetId()) {
+ lNodesAnnouncingHeaderAndIDs.erase(it);
+ lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId());
return;
+ }
+ }
bool fAnnounceUsingCMPCTBLOCK = false;
uint64_t nCMPCTBLOCKVersion = (pfrom->GetLocalServices() & NODE_WITNESS) ? 2 : 1;
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
@@ -1273,6 +1281,10 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
if (fRequireStandard && !AreInputsStandard(tx, view))
return state.Invalid(false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs");
+ // Check for non-standard witness in P2WSH
+ if (!tx.wit.IsNull() && fRequireStandard && !IsWitnessStandard(tx, view))
+ return state.DoS(0, false, REJECT_NONSTANDARD, "bad-witness-nonstandard", true);
+
int64_t nSigOpsCost = GetTransactionSigOpCost(tx, view, STANDARD_SCRIPT_VERIFY_FLAGS);
CAmount nValueOut = tx.GetValueOut();
@@ -1555,7 +1567,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
}
}
- SyncWithWallets(tx, NULL);
+ GetMainSignals().SyncTransaction(tx, NULL, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
return true;
}
@@ -1846,10 +1858,10 @@ void Misbehaving(NodeId pnode, int howmuch)
int banscore = GetArg("-banscore", DEFAULT_BANSCORE_THRESHOLD);
if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore)
{
- LogPrintf("%s: %s (%d -> %d) BAN THRESHOLD EXCEEDED\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior);
+ LogPrintf("%s: %s peer=%d (%d -> %d) BAN THRESHOLD EXCEEDED\n", __func__, state->name, pnode, state->nMisbehavior-howmuch, state->nMisbehavior);
state->fShouldBan = true;
} else
- LogPrintf("%s: %s (%d -> %d)\n", __func__, state->name, state->nMisbehavior-howmuch, state->nMisbehavior);
+ LogPrintf("%s: %s peer=%d (%d -> %d)\n", __func__, state->name, pnode, state->nMisbehavior-howmuch, state->nMisbehavior);
}
void static InvalidChainFound(CBlockIndex* pindexNew)
@@ -1870,17 +1882,6 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
}
void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
- int nDoS = 0;
- if (state.IsInvalid(nDoS)) {
- std::map<uint256, NodeId>::iterator it = mapBlockSource.find(pindex->GetBlockHash());
- if (it != mapBlockSource.end() && State(it->second)) {
- assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
- CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()};
- State(it->second)->rejects.push_back(reject);
- if (nDoS > 0)
- Misbehaving(it->second, nDoS);
- }
- }
if (!state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(pindex);
@@ -2788,7 +2789,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
// Let wallets know transactions went from 1-confirmed to
// 0-confirmed or conflicted:
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
- SyncWithWallets(tx, pindexDelete->pprev);
+ GetMainSignals().SyncTransaction(tx, pindexDelete->pprev, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
}
return true;
}
@@ -2827,7 +2828,6 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
InvalidBlockFound(pindexNew, state);
return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString());
}
- mapBlockSource.erase(pindexNew->GetBlockHash());
nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2;
LogPrint("bench", " - Connect total: %.2fms [%.2fs]\n", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001);
assert(view.Flush());
@@ -3026,7 +3026,7 @@ static void NotifyHeaderTip() {
* or an activated best chain. pblock is either NULL or a pointer to a block
* that is already loaded (to avoid loading it again from disk).
*/
-bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock, CConnman* connman) {
+bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock) {
CBlockIndex *pindexMostWork = NULL;
CBlockIndex *pindexNewTip = NULL;
std::vector<std::tuple<CTransaction,CBlockIndex*,int>> txChanged;
@@ -3041,7 +3041,6 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
const CBlockIndex *pindexFork;
std::list<CTransaction> txConflicted;
bool fInitialDownload;
- int nNewHeight;
{
LOCK(cs_main);
CBlockIndex *pindexOldTip = chainActive.Tip();
@@ -3064,59 +3063,27 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
pindexNewTip = chainActive.Tip();
pindexFork = chainActive.FindFork(pindexOldTip);
fInitialDownload = IsInitialBlockDownload();
- nNewHeight = chainActive.Height();
}
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
// Notifications/callbacks that can run without cs_main
- if(connman)
- connman->SetBestHeight(nNewHeight);
// throw all transactions though the signal-interface
// while _not_ holding the cs_main lock
BOOST_FOREACH(const CTransaction &tx, txConflicted)
{
- SyncWithWallets(tx, pindexNewTip);
+ GetMainSignals().SyncTransaction(tx, pindexNewTip, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
}
// ... and about transactions that got confirmed:
for(unsigned int i = 0; i < txChanged.size(); i++)
- SyncWithWallets(std::get<0>(txChanged[i]), std::get<1>(txChanged[i]), std::get<2>(txChanged[i]));
+ GetMainSignals().SyncTransaction(std::get<0>(txChanged[i]), std::get<1>(txChanged[i]), std::get<2>(txChanged[i]));
+
+ // Notify external listeners about the new tip.
+ GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
// Always notify the UI if a new block tip was connected
if (pindexFork != pindexNewTip) {
uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);
-
- if (!fInitialDownload) {
- // Find the hashes of all blocks that weren't previously in the best chain.
- std::vector<uint256> vHashes;
- CBlockIndex *pindexToAnnounce = pindexNewTip;
- while (pindexToAnnounce != pindexFork) {
- vHashes.push_back(pindexToAnnounce->GetBlockHash());
- pindexToAnnounce = pindexToAnnounce->pprev;
- if (vHashes.size() == MAX_BLOCKS_TO_ANNOUNCE) {
- // Limit announcements in case of a huge reorganization.
- // Rely on the peer's synchronization mechanism in that case.
- break;
- }
- }
- // Relay inventory, but don't relay old inventory during initial block download.
- int nBlockEstimate = 0;
- if (fCheckpointsEnabled)
- nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints());
- if(connman) {
- connman->ForEachNode([nNewHeight, nBlockEstimate, &vHashes](CNode* pnode) {
- if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) {
- BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) {
- pnode->PushBlockHash(hash);
- }
- }
- });
- }
- // Notify external listeners about the new tip.
- if (!vHashes.empty()) {
- GetMainSignals().UpdatedBlockTip(pindexNewTip);
- }
- }
}
} while (pindexNewTip != pindexMostWork);
CheckBlockIndex(chainparams.GetConsensus());
@@ -3129,6 +3096,36 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
return true;
}
+
+bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex)
+{
+ {
+ LOCK(cs_main);
+ if (pindex->nChainWork < chainActive.Tip()->nChainWork) {
+ // Nothing to do, this block is not at the tip.
+ return true;
+ }
+ if (chainActive.Tip()->nChainWork > nLastPreciousChainwork) {
+ // The chain has been extended since the last call, reset the counter.
+ nBlockReverseSequenceId = -1;
+ }
+ nLastPreciousChainwork = chainActive.Tip()->nChainWork;
+ setBlockIndexCandidates.erase(pindex);
+ pindex->nSequenceId = nBlockReverseSequenceId;
+ if (nBlockReverseSequenceId > std::numeric_limits<int32_t>::min()) {
+ // We can't keep reducing the counter if somebody really wants to
+ // call preciousblock 2**31-1 times on the same set of tips...
+ nBlockReverseSequenceId--;
+ }
+ if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS) && pindex->nChainTx) {
+ setBlockIndexCandidates.insert(pindex);
+ PruneBlockIndexCandidates();
+ }
+ }
+
+ return ActivateBestChain(state, params);
+}
+
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
{
AssertLockHeld(cs_main);
@@ -3745,7 +3742,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
return true;
}
-bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, CConnman* connman)
+bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp)
{
{
LOCK(cs_main);
@@ -3767,7 +3764,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C
NotifyHeaderTip();
- if (!ActivateBestChain(state, chainparams, pblock, connman))
+ if (!ActivateBestChain(state, chainparams, pblock))
return error("%s: ActivateBestChain failed", __func__);
return true;
@@ -4523,7 +4520,7 @@ void static CheckBlockIndex(const Consensus::Params& consensusParams)
assert(pindex->GetBlockHash() == consensusParams.hashGenesisBlock); // Genesis block's hash must match.
assert(pindex == chainActive.Genesis()); // The current active chain's genesis block must be this block.
}
- if (pindex->nChainTx == 0) assert(pindex->nSequenceId == 0); // nSequenceId can't be set for blocks that aren't linked
+ if (pindex->nChainTx == 0) assert(pindex->nSequenceId <= 0); // nSequenceId can't be set positive for blocks that aren't linked (negative is used for preciousblock)
// VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred).
// HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred.
if (!fHavePruned) {
@@ -4702,6 +4699,59 @@ std::string GetWarnings(const std::string& strFor)
//////////////////////////////////////////////////////////////////////////////
//
+// blockchain -> download logic notification
+//
+
+void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
+ const int nNewHeight = pindexNew->nHeight;
+ connman->SetBestHeight(nNewHeight);
+
+ if (!fInitialDownload) {
+ // Find the hashes of all blocks that weren't previously in the best chain.
+ std::vector<uint256> vHashes;
+ const CBlockIndex *pindexToAnnounce = pindexNew;
+ while (pindexToAnnounce != pindexFork) {
+ vHashes.push_back(pindexToAnnounce->GetBlockHash());
+ pindexToAnnounce = pindexToAnnounce->pprev;
+ if (vHashes.size() == MAX_BLOCKS_TO_ANNOUNCE) {
+ // Limit announcements in case of a huge reorganization.
+ // Rely on the peer's synchronization mechanism in that case.
+ break;
+ }
+ }
+ // Relay inventory, but don't relay old inventory during initial block download.
+ connman->ForEachNode([nNewHeight, &vHashes](CNode* pnode) {
+ if (nNewHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 0)) {
+ BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) {
+ pnode->PushBlockHash(hash);
+ }
+ }
+ });
+ }
+}
+
+void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationState& state) {
+ LOCK(cs_main);
+
+ const uint256 hash(block.GetHash());
+ std::map<uint256, NodeId>::iterator it = mapBlockSource.find(hash);
+
+ int nDoS = 0;
+ if (state.IsInvalid(nDoS)) {
+ if (it != mapBlockSource.end() && State(it->second)) {
+ assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
+ CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), hash};
+ State(it->second)->rejects.push_back(reject);
+ if (nDoS > 0)
+ Misbehaving(it->second, nDoS);
+ }
+ }
+ if (it != mapBlockSource.end())
+ mapBlockSource.erase(it);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
// Messages
//
@@ -4758,6 +4808,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma
uint64_t hashAddr = addr.GetHash();
std::multimap<uint64_t, CNode*> mapMix;
const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
+ FastRandomContext insecure_rand;
auto sortfunc = [&mapMix, &hasher](CNode* pnode) {
if (pnode->nVersion >= CADDR_TIME_VERSION) {
@@ -4766,9 +4817,9 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma
}
};
- auto pushfunc = [&addr, &mapMix, &nRelayNodes] {
+ auto pushfunc = [&addr, &mapMix, &nRelayNodes, &insecure_rand] {
for (auto mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
- mi->second->PushAddress(addr);
+ mi->second->PushAddress(addr, insecure_rand);
};
connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
@@ -4870,7 +4921,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// and we don't feel like constructing the object for them, so
// instead we respond with the full, non-compact block.
bool fPeerWantsWitness = State(pfrom->GetId())->fWantsCmpctWitness;
- if (mi->second->nHeight >= chainActive.Height() - 10) {
+ if (CanDirectFetch(consensusParams) && mi->second->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) {
CBlockHeaderAndShortTxIDs cmpctblock(block, fPeerWantsWitness);
pfrom->PushMessageWithFlag(fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
} else
@@ -5078,14 +5129,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (fListen && !IsInitialBlockDownload())
{
CAddress addr = GetLocalAddress(&pfrom->addr, pfrom->GetLocalServices());
+ FastRandomContext insecure_rand;
if (addr.IsRoutable())
{
LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString());
- pfrom->PushAddress(addr);
+ pfrom->PushAddress(addr, insecure_rand);
} else if (IsPeerAddrLocalGood(pfrom)) {
addr.SetIP(pfrom->addrLocal);
LogPrint("net", "ProcessMessages: advertising address %s\n", addr.ToString());
- pfrom->PushAddress(addr);
+ pfrom->PushAddress(addr, insecure_rand);
}
}
@@ -5397,8 +5449,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return true;
}
- if (it->second->nHeight < chainActive.Height() - 15) {
- LogPrint("net", "Peer %d sent us a getblocktxn for a block > 15 deep", pfrom->id);
+ if (it->second->nHeight < chainActive.Height() - MAX_BLOCKTXN_DEPTH) {
+ LogPrint("net", "Peer %d sent us a getblocktxn for a block > %i deep", pfrom->id, MAX_BLOCKTXN_DEPTH);
return true;
}
@@ -5727,6 +5779,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return true;
}
+ if (!fAlreadyInFlight && mapBlocksInFlight.size() == 1 && pindex->pprev->IsValid(BLOCK_VALID_CHAIN)) {
+ // We seem to be rather well-synced, so it appears pfrom was the first to provide us
+ // with this block! Let's get them to announce using compact blocks in the future.
+ MaybeSetPeerAsAnnouncingHeaderAndIDs(nodestate, pfrom, connman);
+ }
+
BlockTransactionsRequest req;
for (size_t i = 0; i < cmpctblock.BlockTxCount(); i++) {
if (!partialBlock.IsTxAvailable(i))
@@ -5795,7 +5853,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->PushMessage(NetMsgType::GETDATA, invs);
} else {
CValidationState state;
- ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL, &connman);
+ ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL);
int nDoS;
if (state.IsInvalid(nDoS)) {
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
@@ -5971,7 +6029,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// Such an unrequested block may still be processed, subject to the
// conditions in AcceptBlock().
bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload();
- ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL, &connman);
+ ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL);
int nDoS;
if (state.IsInvalid(nDoS)) {
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
@@ -6008,8 +6066,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->vAddrToSend.clear();
vector<CAddress> vAddr = connman.GetAddresses();
+ FastRandomContext insecure_rand;
BOOST_FOREACH(const CAddress &addr, vAddr)
- pfrom->PushAddress(addr);
+ pfrom->PushAddress(addr, insecure_rand);
}
@@ -6842,7 +6901,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
// until scheduled broadcast, then move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY.
else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < pto->nextSendTimeFeeFilter &&
(currentFilter < 3 * pto->lastSentFeeFilter / 4 || currentFilter > 4 * pto->lastSentFeeFilter / 3)) {
- pto->nextSendTimeFeeFilter = timeNow + (insecure_rand() % MAX_FEEFILTER_CHANGE_DELAY) * 1000000;
+ pto->nextSendTimeFeeFilter = timeNow + GetRandInt(MAX_FEEFILTER_CHANGE_DELAY) * 1000000;
}
}
}
@@ -6859,6 +6918,12 @@ ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::D
return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache);
}
+int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos)
+{
+ LOCK(cs_main);
+ return VersionBitsStateSinceHeight(chainActive.Tip(), params, pos, versionbitscache);
+}
+
class CMainCleanup
{
public:
diff --git a/src/main.h b/src/main.h
index 2646d8f86b..3eab9b89da 100644
--- a/src/main.h
+++ b/src/main.h
@@ -16,6 +16,7 @@
#include "net.h"
#include "script/script_error.h"
#include "sync.h"
+#include "validationinterface.h"
#include "versionbits.h"
#include <algorithm>
@@ -41,7 +42,6 @@ class CValidationInterface;
class CValidationState;
struct PrecomputedTransactionData;
-struct CNodeStateStats;
struct LockPoints;
/** Default for DEFAULT_WHITELISTRELAY. */
@@ -90,6 +90,11 @@ static const unsigned int BLOCK_STALLING_TIMEOUT = 2;
/** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends
* less than this number, we reached its tip. Changing this value is a protocol upgrade. */
static const unsigned int MAX_HEADERS_RESULTS = 2000;
+/** Maximum depth of blocks we're willing to serve as compact blocks to peers
+ * when requested. For older blocks, a regular BLOCK response will be sent. */
+static const int MAX_CMPCTBLOCK_DEPTH = 5;
+/** Maximum depth of blocks we're willing to respond to GETBLOCKTXN requests for. */
+static const int MAX_BLOCKTXN_DEPTH = 10;
/** Size of the "block download window": how far ahead of our current height do we fetch?
* Larger windows tolerate larger download speed differences between peer, but increase the potential
* degree of disordering of blocks on disk (which make reindexing and in the future perhaps pruning
@@ -206,11 +211,6 @@ static const unsigned int DEFAULT_CHECKLEVEL = 3;
// Setting the target to > than 550MB will make it likely we can respect the target.
static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
-/** Register with a network node to receive its signals */
-void RegisterNodeSignals(CNodeSignals& nodeSignals);
-/** Unregister a network node */
-void UnregisterNodeSignals(CNodeSignals& nodeSignals);
-
/**
* Process an incoming block. This only returns after the best known valid
* block is made active. Note that it does not, however, guarantee that the
@@ -223,7 +223,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals);
* @param[out] dbp The already known disk position of pblock, or NULL if not yet stored.
* @return True if state.IsValid()
*/
-bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, CConnman* connman);
+bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp);
/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
/** Open a block file (blk?????.dat) */
@@ -240,15 +240,6 @@ bool InitBlockIndex(const CChainParams& chainparams);
bool LoadBlockIndex();
/** Unload database information */
void UnloadBlockIndex();
-/** Process protocol messages received from a given node */
-bool ProcessMessages(CNode* pfrom, CConnman& connman);
-/**
- * Send queued protocol messages to be sent to a give node.
- *
- * @param[in] pto The node which we are sending messages to.
- * @param[in] connman The connection manager for that node.
- */
-bool SendMessages(CNode* pto, CConnman& connman);
/** Run an instance of the script checking thread */
void ThreadScriptCheck();
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
@@ -264,7 +255,7 @@ 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, const Consensus::Params& params, uint256 &hashBlock, bool fAllowSlow = false);
/** Find the best known block, and make it the tip of the block chain */
-bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL, CConnman* connman = NULL);
+bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, const CBlock* pblock = NULL);
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
/**
@@ -291,10 +282,6 @@ void UnlinkPrunedFiles(std::set<int>& setFilesToPrune);
/** Create a new block index entry for a given block hash */
CBlockIndex * InsertBlockIndex(uint256 hash);
-/** Get statistics from node state */
-bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
-/** Increase a node's misbehavior score. */
-void Misbehaving(NodeId nodeid, int howmuch);
/** Flush all state, indexes and buffers to disk. */
void FlushStateToDisk();
/** Prune block files and flush state to disk. */
@@ -310,14 +297,8 @@ std::string FormatStateMessage(const CValidationState &state);
/** Get the BIP9 state for a given deployment at the current tip. */
ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::DeploymentPos pos);
-struct CNodeStateStats {
- int nMisbehavior;
- int nSyncHeight;
- int nCommonHeight;
- std::vector<int> vHeightInFlight;
-};
-
-
+/** Get the block height at which the BIP9 deployment switched into the state for the block building on the current tip. */
+int VersionBitsTipStateSinceHeight(const Consensus::Params& params, Consensus::DeploymentPos pos);
/**
* Count ECDSA signature operations the old-fashioned (pre-0.6) way
@@ -504,6 +485,9 @@ public:
/** Find the last common block between the parameter chain and a locator. */
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator);
+/** Mark a block as precious and reorganize. */
+bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex);
+
/** Mark a block as invalid. */
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex);
@@ -545,4 +529,45 @@ static const unsigned int REJECT_ALREADY_KNOWN = 0x101;
/** Transaction conflicts with a transaction already known */
static const unsigned int REJECT_CONFLICT = 0x102;
+// The following things handle network-processing logic
+// (and should be moved to a separate file)
+
+/** Register with a network node to receive its signals */
+void RegisterNodeSignals(CNodeSignals& nodeSignals);
+/** Unregister a network node */
+void UnregisterNodeSignals(CNodeSignals& nodeSignals);
+
+class PeerLogicValidation : public CValidationInterface {
+private:
+ CConnman* connman;
+
+public:
+ PeerLogicValidation(CConnman* connmanIn) : connman(connmanIn) {}
+
+ virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload);
+ virtual void BlockChecked(const CBlock& block, const CValidationState& state);
+};
+
+struct CNodeStateStats {
+ int nMisbehavior;
+ int nSyncHeight;
+ int nCommonHeight;
+ std::vector<int> vHeightInFlight;
+};
+
+/** Get statistics from node state */
+bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
+/** Increase a node's misbehavior score. */
+void Misbehaving(NodeId nodeid, int howmuch);
+
+/** Process protocol messages received from a given node */
+bool ProcessMessages(CNode* pfrom, CConnman& connman);
+/**
+ * Send queued protocol messages to be sent to a give node.
+ *
+ * @param[in] pto The node which we are sending messages to.
+ * @param[in] connman The connection manager for that node.
+ */
+bool SendMessages(CNode* pto, CConnman& connman);
+
#endif // BITCOIN_MAIN_H
diff --git a/src/miner.cpp b/src/miner.cpp
index 9575858840..ebf2f21ffd 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -29,6 +29,7 @@
#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <queue>
+#include <utility>
using namespace std;
@@ -122,14 +123,14 @@ void BlockAssembler::resetBlock()
blockFinished = false;
}
-CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
+std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
{
resetBlock();
pblocktemplate.reset(new CBlockTemplate());
if(!pblocktemplate.get())
- return NULL;
+ return nullptr;
pblock = &pblocktemplate->block; // pointer for convenience
// Add dummy coinbase tx as first transaction
@@ -194,7 +195,7 @@ CBlockTemplate* BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state)));
}
- return pblocktemplate.release();
+ return std::move(pblocktemplate);
}
bool BlockAssembler::isStillDependent(CTxMemPool::txiter iter)
diff --git a/src/miner.h b/src/miner.h
index 11753f5e43..bad443b82a 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -164,7 +164,7 @@ private:
public:
BlockAssembler(const CChainParams& chainparams);
/** Construct a new block template with coinbase to scriptPubKeyIn */
- CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn);
+ std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn);
private:
// utility functions
diff --git a/src/net.cpp b/src/net.cpp
index 19dd040997..1bca168d1d 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -187,7 +187,8 @@ void AdvertiseLocal(CNode *pnode)
if (addrLocal.IsRoutable())
{
LogPrint("net", "AdvertiseLocal: advertising address %s\n", addrLocal.ToString());
- pnode->PushAddress(addrLocal);
+ FastRandomContext insecure_rand;
+ pnode->PushAddress(addrLocal, insecure_rand);
}
}
}
@@ -659,7 +660,7 @@ void CNode::copyStats(CNodeStats &stats)
// Raw ping time is in microseconds, but show it to user as whole seconds (Bitcoin users should be well used to small numbers with many decimal places by now :)
stats.dPingTime = (((double)nPingUsecTime) / 1e6);
- stats.dPingMin = (((double)nMinPingUsecTime) / 1e6);
+ stats.dMinPing = (((double)nMinPingUsecTime) / 1e6);
stats.dPingWait = (((double)nPingUsecWait) / 1e6);
// Leave string empty if addrLocal invalid (not filled in yet)
@@ -1454,6 +1455,7 @@ static std::string GetDNSHost(const CDNSSeedData& data, ServiceFlags* requiredSe
return data.host;
}
+ // See chainparams.cpp, most dnsseeds only support one or two possible servicebits hostnames
return strprintf("x%x.%s", *requiredServiceBits, data.host);
}
@@ -1461,12 +1463,19 @@ static std::string GetDNSHost(const CDNSSeedData& data, ServiceFlags* requiredSe
void CConnman::ThreadDNSAddressSeed()
{
// goal: only query DNS seeds if address need is acute
+ // Avoiding DNS seeds when we don't need them improves user privacy by
+ // creating fewer identifying DNS requests, reduces trust by giving seeds
+ // less influence on the network topology, and reduces traffic to the seeds.
if ((addrman.size() > 0) &&
(!GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED))) {
MilliSleep(11 * 1000);
LOCK(cs_vNodes);
- if (vNodes.size() >= 2) {
+ int nRelevant = 0;
+ for (auto pnode : vNodes) {
+ nRelevant += pnode->fSuccessfullyConnected && ((pnode->nServices & nRelevantServices) == nRelevantServices);
+ }
+ if (nRelevant >= 2) {
LogPrintf("P2P peers available. Skipped DNS seeding.\n");
return;
}
@@ -1621,7 +1630,6 @@ void CConnman::ThreadOpenConnections()
}
}
}
- assert(nOutbound <= (nMaxOutbound + nMaxFeeler));
// Feeler Connections
//
@@ -1674,8 +1682,8 @@ void CConnman::ThreadOpenConnections()
if (nANow - addr.nLastTry < 600 && nTries < 30)
continue;
- // only consider nodes missing relevant services after 40 failed attempts
- if ((addr.nServices & nRelevantServices) != nRelevantServices && nTries < 40)
+ // only consider nodes missing relevant services after 40 failed attempts and only if less than half the outbound are up.
+ if ((addr.nServices & nRelevantServices) != nRelevantServices && (nTries < 40 || nOutbound >= (nMaxOutbound >> 1)))
continue;
// do not allow non-default ports, unless after 50 invalid addresses selected already
diff --git a/src/net.h b/src/net.h
index 67f0abe4be..58b492e592 100644
--- a/src/net.h
+++ b/src/net.h
@@ -503,7 +503,7 @@ public:
bool fWhitelisted;
double dPingTime;
double dPingWait;
- double dPingMin;
+ double dMinPing;
std::string addrLocal;
CAddress addr;
};
@@ -735,14 +735,14 @@ public:
addrKnown.insert(_addr.GetKey());
}
- void PushAddress(const CAddress& _addr)
+ void PushAddress(const CAddress& _addr, FastRandomContext &insecure_rand)
{
// Known checking here is only to save space from duplicates.
// SendMessages will filter it again for knowns that were added
// after addresses were pushed.
if (_addr.IsValid() && !addrKnown.contains(_addr.GetKey())) {
if (vAddrToSend.size() >= MAX_ADDR_TO_SEND) {
- vAddrToSend[insecure_rand() % vAddrToSend.size()] = _addr;
+ vAddrToSend[insecure_rand.rand32() % vAddrToSend.size()] = _addr;
} else {
vAddrToSend.push_back(_addr);
}
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 7d7f1b6788..9fe34108f5 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -596,8 +596,8 @@ static bool ConnectThroughProxy(const proxyType &proxy, const std::string& strDe
// do socks negotiation
if (proxy.randomize_credentials) {
ProxyCredentials random_auth;
- random_auth.username = strprintf("%i", insecure_rand());
- random_auth.password = strprintf("%i", insecure_rand());
+ static std::atomic_int counter;
+ random_auth.username = random_auth.password = strprintf("%i", counter++);
if (!Socks5(strDest, (unsigned short)port, &random_auth, hSocket))
return false;
} else {
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
index 7b0e8b7d08..c07cd2eff8 100644
--- a/src/policy/fees.cpp
+++ b/src/policy/fees.cpp
@@ -594,7 +594,7 @@ FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
CAmount FeeFilterRounder::round(CAmount currentMinFee)
{
std::set<double>::iterator it = feeset.lower_bound(currentMinFee);
- if ((it != feeset.begin() && insecure_rand() % 3 != 0) || it == feeset.end()) {
+ if ((it != feeset.begin() && insecure_rand.rand32() % 3 != 0) || it == feeset.end()) {
it--;
}
return *it;
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 463f62f710..2c1ac3b934 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -7,6 +7,7 @@
#include "amount.h"
#include "uint256.h"
+#include "random.h"
#include <map>
#include <string>
@@ -298,5 +299,6 @@ public:
private:
std::set<double> feeset;
+ FastRandomContext insecure_rand;
};
#endif /*BITCOIN_POLICYESTIMATOR_H */
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 48080abc77..ae42b2bd74 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin developers
+// Copyright (c) 2009-2016 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -154,6 +154,58 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
return true;
}
+bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
+{
+ if (tx.IsCoinBase())
+ return true; // Coinbases are skipped
+
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
+ {
+ // We don't care if witness for this input is empty, since it must not be bloated.
+ // If the script is invalid without witness, it would be caught sooner or later during validation.
+ if (tx.wit.vtxinwit[i].IsNull())
+ continue;
+
+ const CTxOut &prev = mapInputs.GetOutputFor(tx.vin[i]);
+
+ // get the scriptPubKey corresponding to this input:
+ CScript prevScript = prev.scriptPubKey;
+
+ if (prevScript.IsPayToScriptHash()) {
+ std::vector <std::vector<unsigned char> > stack;
+ // If the scriptPubKey is P2SH, we try to extract the redeemScript casually by converting the scriptSig
+ // into a stack. We do not check IsPushOnly nor compare the hash as these will be done later anyway.
+ // If the check fails at this stage, we know that this txid must be a bad one.
+ if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SIGVERSION_BASE))
+ return false;
+ if (stack.empty())
+ return false;
+ prevScript = CScript(stack.back().begin(), stack.back().end());
+ }
+
+ int witnessversion = 0;
+ std::vector<unsigned char> witnessprogram;
+
+ // Non-witness program must not be associated with any witness
+ if (!prevScript.IsWitnessProgram(witnessversion, witnessprogram))
+ return false;
+
+ // Check P2WSH standard limits
+ if (witnessversion == 0 && witnessprogram.size() == 32) {
+ if (tx.wit.vtxinwit[i].scriptWitness.stack.back().size() > MAX_STANDARD_P2WSH_SCRIPT_SIZE)
+ return false;
+ size_t sizeWitnessStack = tx.wit.vtxinwit[i].scriptWitness.stack.size() - 1;
+ if (sizeWitnessStack > MAX_STANDARD_P2WSH_STACK_ITEMS)
+ return false;
+ for (unsigned int j = 0; j < sizeWitnessStack; j++) {
+ if (tx.wit.vtxinwit[i].scriptWitness.stack[j].size() > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE)
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost)
diff --git a/src/policy/policy.h b/src/policy/policy.h
index 9d6ff1233b..814e6c0b6f 100644
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin developers
+// Copyright (c) 2009-2016 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -30,6 +30,12 @@ static const unsigned int MAX_STANDARD_TX_SIGOPS_COST = MAX_BLOCK_SIGOPS_COST/5;
static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300;
/** Default for -bytespersigop */
static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;
+/** The maximum number of witness stack items in a standard P2WSH script */
+static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS = 100;
+/** The maximum size of each witness stack item in a standard P2WSH script */
+static const unsigned int MAX_STANDARD_P2WSH_STACK_ITEM_SIZE = 80;
+/** The maximum size of a standard witnessScript */
+static const unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600;
/**
* Standard script verification flags that standard transactions will comply
* with. However scripts violating these flags may still be present in valid
@@ -48,7 +54,8 @@ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY
SCRIPT_VERIFY_CHECKSEQUENCEVERIFY |
SCRIPT_VERIFY_LOW_S |
SCRIPT_VERIFY_WITNESS |
- SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM;
+ SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM |
+ SCRIPT_VERIFY_WITNESS_PUBKEYTYPE;
/** For convenience, standard but not mandatory verify flags. */
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
@@ -69,6 +76,12 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnes
* @return True if all inputs (scriptSigs) use only standard transaction forms
*/
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
+ /**
+ * Check if the transaction is over standard P2WSH resources limit:
+ * 3600bytes witnessScript size, 80bytes per witness stack element, 100 witness stack elements
+ * These limits are adequate for multi-signature up to n-of-100 using OP_CHECKSIG, OP_ADD, and OP_EQUAL,
+ */
+bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
extern unsigned int nBytesPerSigOp;
diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui
index 9dc641979e..8be4a955b3 100644
--- a/src/qt/forms/debugwindow.ui
+++ b/src/qt/forms/debugwindow.ui
@@ -1353,13 +1353,36 @@
</widget>
</item>
<item row="16" column="0">
+ <widget class="QLabel" name="peerMinPingLabel">
+ <property name="text">
+ <string>Min Ping</string>
+ </property>
+ </widget>
+ </item>
+ <item row="16" column="2">
+ <widget class="QLabel" name="peerMinPing">
+ <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="17" column="0">
<widget class="QLabel" name="label_timeoffset">
<property name="text">
<string>Time Offset</string>
</property>
</widget>
</item>
- <item row="16" column="2">
+ <item row="17" column="2">
<widget class="QLabel" name="timeoffset">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1375,7 +1398,7 @@
</property>
</widget>
</item>
- <item row="17" column="1">
+ <item row="18" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui
index 923ed68996..710801ee96 100644
--- a/src/qt/forms/overviewpage.ui
+++ b/src/qt/forms/overviewpage.ui
@@ -20,7 +20,7 @@
<bool>false</bool>
</property>
<property name="styleSheet">
- <string notr="true">background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000;</string>
+ <string notr="true">QLabel { background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; }</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -28,6 +28,9 @@
<property name="margin">
<number>3</number>
</property>
+ <property name="textInteractionFlags">
+ <set>Qt::TextSelectableByMouse</set>
+ </property>
</widget>
</item>
<item>
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 0beaddf997..42dafa1175 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -947,7 +947,7 @@ QString formatServicesStr(quint64 mask)
QString formatPingTime(double dPingTime)
{
- return dPingTime == 0 ? QObject::tr("N/A") : QString(QObject::tr("%1 ms")).arg(QString::number((int)(dPingTime * 1000), 10));
+ return (dPingTime == std::numeric_limits<int64_t>::max()/1e6 || dPingTime == 0) ? QObject::tr("N/A") : QString(QObject::tr("%1 ms")).arg(QString::number((int)(dPingTime * 1000), 10));
}
QString formatTimeOffset(int64_t nTimeOffset)
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index a820bd791f..a2f9471fcc 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -31,7 +31,7 @@ bool NodeLessThan::operator()(const CNodeCombinedStats &left, const CNodeCombine
case PeerTableModel::Subversion:
return pLeft->cleanSubVer.compare(pRight->cleanSubVer) < 0;
case PeerTableModel::Ping:
- return pLeft->dPingTime < pRight->dPingTime;
+ return pLeft->dMinPing < pRight->dMinPing;
}
return false;
@@ -113,7 +113,7 @@ PeerTableModel::PeerTableModel(ClientModel *parent) :
clientModel(parent),
timer(0)
{
- columns << tr("NodeId") << tr("Node/Service") << tr("User Agent") << tr("Ping Time");
+ columns << tr("NodeId") << tr("Node/Service") << tr("User Agent") << tr("Ping");
priv = new PeerTablePriv();
// default to unsorted
priv->sortColumn = -1;
@@ -166,7 +166,7 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const
case Subversion:
return QString::fromStdString(rec->nodeStats.cleanSubVer);
case Ping:
- return GUIUtil::formatPingTime(rec->nodeStats.dPingTime);
+ return GUIUtil::formatPingTime(rec->nodeStats.dMinPing);
}
} else if (role == Qt::TextAlignmentRole) {
if (index.column() == Ping)
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 5c6dc97b20..b50cad4975 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -43,18 +43,21 @@ ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *_platformStyle, QWid
}
// context menu actions
+ QAction *copyURIAction = new QAction(tr("Copy URI"), this);
QAction *copyLabelAction = new QAction(tr("Copy label"), this);
QAction *copyMessageAction = new QAction(tr("Copy message"), this);
QAction *copyAmountAction = new QAction(tr("Copy amount"), this);
// context menu
contextMenu = new QMenu();
+ contextMenu->addAction(copyURIAction);
contextMenu->addAction(copyLabelAction);
contextMenu->addAction(copyMessageAction);
contextMenu->addAction(copyAmountAction);
// context menu signals
connect(ui->recentRequestsView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showMenu(QPoint)));
+ connect(copyURIAction, SIGNAL(triggered()), this, SLOT(copyURI()));
connect(copyLabelAction, SIGNAL(triggered()), this, SLOT(copyLabel()));
connect(copyMessageAction, SIGNAL(triggered()), this, SLOT(copyMessage()));
connect(copyAmountAction, SIGNAL(triggered()), this, SLOT(copyAmount()));
@@ -228,30 +231,50 @@ void ReceiveCoinsDialog::keyPressEvent(QKeyEvent *event)
this->QDialog::keyPressEvent(event);
}
-// copy column of selected row to clipboard
-void ReceiveCoinsDialog::copyColumnToClipboard(int column)
+QModelIndex ReceiveCoinsDialog::selectedRow()
{
if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
- return;
+ return QModelIndex();
QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
if(selection.empty())
- return;
+ return QModelIndex();
// correct for selection mode ContiguousSelection
QModelIndex firstIndex = selection.at(0);
+ return firstIndex;
+}
+
+// copy column of selected row to clipboard
+void ReceiveCoinsDialog::copyColumnToClipboard(int column)
+{
+ QModelIndex firstIndex = selectedRow();
+ if (!firstIndex.isValid()) {
+ return;
+ }
GUIUtil::setClipboard(model->getRecentRequestsTableModel()->data(firstIndex.child(firstIndex.row(), column), Qt::EditRole).toString());
}
// context menu
void ReceiveCoinsDialog::showMenu(const QPoint &point)
{
- if(!model || !model->getRecentRequestsTableModel() || !ui->recentRequestsView->selectionModel())
- return;
- QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
- if(selection.empty())
+ if (!selectedRow().isValid()) {
return;
+ }
contextMenu->exec(QCursor::pos());
}
+// context menu action: copy URI
+void ReceiveCoinsDialog::copyURI()
+{
+ QModelIndex sel = selectedRow();
+ if (!sel.isValid()) {
+ return;
+ }
+
+ const RecentRequestsTableModel * const submodel = model->getRecentRequestsTableModel();
+ const QString uri = GUIUtil::formatBitcoinURI(submodel->entry(sel.row()).recipient);
+ GUIUtil::setClipboard(uri);
+}
+
// context menu action: copy label
void ReceiveCoinsDialog::copyLabel()
{
diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h
index 226fd65cfa..d137f1616e 100644
--- a/src/qt/receivecoinsdialog.h
+++ b/src/qt/receivecoinsdialog.h
@@ -60,6 +60,7 @@ private:
QMenu *contextMenu;
const PlatformStyle *platformStyle;
+ QModelIndex selectedRow();
void copyColumnToClipboard(int column);
virtual void resizeEvent(QResizeEvent *event);
@@ -71,6 +72,7 @@ private Q_SLOTS:
void recentRequestsView_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void updateDisplayUnit();
void showMenu(const QPoint &point);
+ void copyURI();
void copyLabel();
void copyMessage();
void copyAmount();
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index b6ed75535c..f10dddf589 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -246,7 +246,10 @@ bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string
std::string strPrint;
// Convert argument list to JSON objects in method-dependent way,
// and pass it along with the method name to the dispatcher.
- lastResult = tableRPC.execute(stack.back()[0], RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end())));
+ JSONRPCRequest req;
+ req.params = RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end()));
+ req.strMethod = stack.back()[0];
+ lastResult = tableRPC.execute(req);
state = STATE_COMMAND_EXECUTED;
curarg.clear();
@@ -895,6 +898,7 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
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->peerMinPing->setText(GUIUtil::formatPingTime(stats->nodeStats.dMinPing));
ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
ui->peerVersion->setText(QString("%1").arg(QString::number(stats->nodeStats.nVersion)));
ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index 4061909b71..3e42f3a7b0 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -142,7 +142,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
}
CKey key;
- if (!pwalletMain->GetKey(keyID, key))
+ if (!model->getPrivKey(keyID, key))
{
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(tr("Private key for the entered address is not available."));
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index e36d86fddd..cd27385653 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -164,9 +164,10 @@ static void ShowProgress(SplashScreen *splash, const std::string &title, int nPr
}
#ifdef ENABLE_WALLET
-static void ConnectWallet(SplashScreen *splash, CWallet* wallet)
+void SplashScreen::ConnectWallet(CWallet* wallet)
{
- wallet->ShowProgress.connect(boost::bind(ShowProgress, splash, _1, _2));
+ wallet->ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
+ connectedWallets.push_back(wallet);
}
#endif
@@ -176,7 +177,7 @@ void SplashScreen::subscribeToCoreSignals()
uiInterface.InitMessage.connect(boost::bind(InitMessage, this, _1));
uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
#ifdef ENABLE_WALLET
- uiInterface.LoadWallet.connect(boost::bind(ConnectWallet, this, _1));
+ uiInterface.LoadWallet.connect(boost::bind(&SplashScreen::ConnectWallet, this, _1));
#endif
}
@@ -186,8 +187,9 @@ void SplashScreen::unsubscribeFromCoreSignals()
uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, _1));
uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
#ifdef ENABLE_WALLET
- if(pwalletMain)
- pwalletMain->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
+ Q_FOREACH(CWallet* const & pwallet, connectedWallets) {
+ pwallet->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
+ }
#endif
}
diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h
index 821f39db1c..d1727b66c9 100644
--- a/src/qt/splashscreen.h
+++ b/src/qt/splashscreen.h
@@ -7,6 +7,7 @@
#include <QSplashScreen>
+class CWallet;
class NetworkStyle;
/** Class for the splashscreen with information of the running client.
@@ -39,11 +40,15 @@ private:
void subscribeToCoreSignals();
/** Disconnect core signals to splash screen */
void unsubscribeFromCoreSignals();
+ /** Connect wallet signals to splash screen */
+ void ConnectWallet(CWallet*);
QPixmap pixmap;
QString curMessage;
QColor curColor;
int curAlignment;
+
+ QList<CWallet*> connectedWallets;
};
#endif // BITCOIN_QT_SPLASHSCREEN_H
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index c8a2cb37ec..305cb4fefa 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -563,6 +563,11 @@ bool WalletModel::havePrivKey(const CKeyID &address) const
return wallet->HaveKey(address);
}
+bool WalletModel::getPrivKey(const CKeyID &address, CKey& vchPrivKeyOut) const
+{
+ return wallet->GetKey(address, vchPrivKeyOut);
+}
+
// returns a list of COutputs from COutPoints
void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs)
{
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index b105c6d991..cdac60da36 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -187,6 +187,7 @@ public:
bool getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
bool havePrivKey(const CKeyID &address) const;
+ bool getPrivKey(const CKeyID &address, CKey& vchPrivKeyOut) const;
void getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs);
bool isSpent(const COutPoint& outpoint) const;
void listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const;
diff --git a/src/random.cpp b/src/random.cpp
index d9a8cc145e..aa027e49c4 100644
--- a/src/random.cpp
+++ b/src/random.cpp
@@ -178,22 +178,21 @@ uint256 GetRandHash()
return hash;
}
-uint32_t insecure_rand_Rz = 11;
-uint32_t insecure_rand_Rw = 11;
-void seed_insecure_rand(bool fDeterministic)
+FastRandomContext::FastRandomContext(bool fDeterministic)
{
// The seed values have some unlikely fixed points which we avoid.
if (fDeterministic) {
- insecure_rand_Rz = insecure_rand_Rw = 11;
+ Rz = Rw = 11;
} else {
uint32_t tmp;
do {
GetRandBytes((unsigned char*)&tmp, 4);
} while (tmp == 0 || tmp == 0x9068ffffU);
- insecure_rand_Rz = tmp;
+ Rz = tmp;
do {
GetRandBytes((unsigned char*)&tmp, 4);
} while (tmp == 0 || tmp == 0x464fffffU);
- insecure_rand_Rw = tmp;
+ Rw = tmp;
}
}
+
diff --git a/src/random.h b/src/random.h
index 31b80bd565..e97d2d1fb0 100644
--- a/src/random.h
+++ b/src/random.h
@@ -28,25 +28,22 @@ uint256 GetRandHash();
void GetStrongRandBytes(unsigned char* buf, int num);
/**
- * Seed insecure_rand using the random pool.
- * @param Deterministic Use a deterministic seed
+ * Fast randomness source. This is seeded once with secure random data, but
+ * is completely deterministic and insecure after that.
+ * This class is not thread-safe.
*/
-void seed_insecure_rand(bool fDeterministic = false);
-
-/**
- * MWC RNG of George Marsaglia
- * This is intended to be fast. It has a period of 2^59.3, though the
- * least significant 16 bits only have a period of about 2^30.1.
- *
- * @return random value
- */
-extern uint32_t insecure_rand_Rz;
-extern uint32_t insecure_rand_Rw;
-static inline uint32_t insecure_rand(void)
-{
- insecure_rand_Rz = 36969 * (insecure_rand_Rz & 65535) + (insecure_rand_Rz >> 16);
- insecure_rand_Rw = 18000 * (insecure_rand_Rw & 65535) + (insecure_rand_Rw >> 16);
- return (insecure_rand_Rw << 16) + insecure_rand_Rz;
-}
+class FastRandomContext {
+public:
+ explicit FastRandomContext(bool fDeterministic=false);
+
+ uint32_t rand32() {
+ Rz = 36969 * (Rz & 65535) + (Rz >> 16);
+ Rw = 18000 * (Rw & 65535) + (Rw >> 16);
+ return (Rw << 16) + Rz;
+ }
+
+ uint32_t Rz;
+ uint32_t Rw;
+};
#endif // BITCOIN_RANDOM_H
diff --git a/src/rest.cpp b/src/rest.cpp
index c815592124..b8b5420626 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -274,7 +274,7 @@ static bool rest_block_notxdetails(HTTPRequest* req, const std::string& strURIPa
}
// A bit of a hack - dependency on a function defined in rpc/blockchain.cpp
-UniValue getblockchaininfo(const UniValue& params, bool fHelp);
+UniValue getblockchaininfo(const JSONRPCRequest& request);
static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart)
{
@@ -285,8 +285,9 @@ static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart)
switch (rf) {
case RF_JSON: {
- UniValue rpcParams(UniValue::VARR);
- UniValue chainInfoObject = getblockchaininfo(rpcParams, false);
+ JSONRPCRequest jsonRequest;
+ jsonRequest.params = UniValue(UniValue::VARR);
+ UniValue chainInfoObject = getblockchaininfo(jsonRequest);
string strJSON = chainInfoObject.write() + "\n";
req->WriteHeader("Content-Type", "application/json");
req->WriteReply(HTTP_OK, strJSON);
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 1e04fcc01c..f538ddcc04 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -146,9 +146,9 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx
return result;
}
-UniValue getblockcount(const UniValue& params, bool fHelp)
+UniValue getblockcount(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getblockcount\n"
"\nReturns the number of blocks in the longest block chain.\n"
@@ -163,9 +163,9 @@ UniValue getblockcount(const UniValue& params, bool fHelp)
return chainActive.Height();
}
-UniValue getbestblockhash(const UniValue& params, bool fHelp)
+UniValue getbestblockhash(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getbestblockhash\n"
"\nReturns the hash of the best (tip) block in the longest block chain.\n"
@@ -190,9 +190,9 @@ void RPCNotifyBlockChange(bool ibd, const CBlockIndex * pindex)
cond_blockchange.notify_all();
}
-UniValue waitfornewblock(const UniValue& params, bool fHelp)
+UniValue waitfornewblock(const JSONRPCRequest& request)
{
- if (fHelp || params.size() > 1)
+ if (request.fHelp || request.params.size() > 1)
throw runtime_error(
"waitfornewblock\n"
"\nWaits for a specific new block and returns useful info about it.\n"
@@ -209,8 +209,8 @@ UniValue waitfornewblock(const UniValue& params, bool fHelp)
+ HelpExampleRpc("waitfornewblock", "1000")
);
int timeout = 0;
- if (params.size() > 0)
- timeout = params[0].get_int();
+ if (request.params.size() > 0)
+ timeout = request.params[0].get_int();
CUpdatedBlock block;
{
@@ -228,9 +228,9 @@ UniValue waitfornewblock(const UniValue& params, bool fHelp)
return ret;
}
-UniValue waitforblock(const UniValue& params, bool fHelp)
+UniValue waitforblock(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"waitforblock\n"
"\nWaits for a specific new block and returns useful info about it.\n"
@@ -249,10 +249,10 @@ UniValue waitforblock(const UniValue& params, bool fHelp)
);
int timeout = 0;
- uint256 hash = uint256S(params[0].get_str());
+ uint256 hash = uint256S(request.params[0].get_str());
- if (params.size() > 1)
- timeout = params[1].get_int();
+ if (request.params.size() > 1)
+ timeout = request.params[1].get_int();
CUpdatedBlock block;
{
@@ -270,9 +270,9 @@ UniValue waitforblock(const UniValue& params, bool fHelp)
return ret;
}
-UniValue waitforblockheight(const UniValue& params, bool fHelp)
+UniValue waitforblockheight(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"waitforblock\n"
"\nWaits for (at least) block height and returns the height and hash\n"
@@ -292,10 +292,10 @@ UniValue waitforblockheight(const UniValue& params, bool fHelp)
);
int timeout = 0;
- int height = params[0].get_int();
+ int height = request.params[0].get_int();
- if (params.size() > 1)
- timeout = params[1].get_int();
+ if (request.params.size() > 1)
+ timeout = request.params[1].get_int();
CUpdatedBlock block;
{
@@ -312,9 +312,9 @@ UniValue waitforblockheight(const UniValue& params, bool fHelp)
return ret;
}
-UniValue getdifficulty(const UniValue& params, bool fHelp)
+UniValue getdifficulty(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getdifficulty\n"
"\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
@@ -411,9 +411,9 @@ UniValue mempoolToJSON(bool fVerbose = false)
}
}
-UniValue getrawmempool(const UniValue& params, bool fHelp)
+UniValue getrawmempool(const JSONRPCRequest& request)
{
- if (fHelp || params.size() > 1)
+ if (request.fHelp || request.params.size() > 1)
throw runtime_error(
"getrawmempool ( verbose )\n"
"\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
@@ -436,15 +436,15 @@ UniValue getrawmempool(const UniValue& params, bool fHelp)
);
bool fVerbose = false;
- if (params.size() > 0)
- fVerbose = params[0].get_bool();
+ if (request.params.size() > 0)
+ fVerbose = request.params[0].get_bool();
return mempoolToJSON(fVerbose);
}
-UniValue getmempoolancestors(const UniValue& params, bool fHelp)
+UniValue getmempoolancestors(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2) {
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
throw runtime_error(
"getmempoolancestors txid (verbose)\n"
"\nIf txid is in the mempool, returns all in-mempool ancestors.\n"
@@ -469,10 +469,10 @@ UniValue getmempoolancestors(const UniValue& params, bool fHelp)
}
bool fVerbose = false;
- if (params.size() > 1)
- fVerbose = params[1].get_bool();
+ if (request.params.size() > 1)
+ fVerbose = request.params[1].get_bool();
- uint256 hash = ParseHashV(params[0], "parameter 1");
+ uint256 hash = ParseHashV(request.params[0], "parameter 1");
LOCK(mempool.cs);
@@ -506,9 +506,9 @@ UniValue getmempoolancestors(const UniValue& params, bool fHelp)
}
}
-UniValue getmempooldescendants(const UniValue& params, bool fHelp)
+UniValue getmempooldescendants(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2) {
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) {
throw runtime_error(
"getmempooldescendants txid (verbose)\n"
"\nIf txid is in the mempool, returns all in-mempool descendants.\n"
@@ -533,10 +533,10 @@ UniValue getmempooldescendants(const UniValue& params, bool fHelp)
}
bool fVerbose = false;
- if (params.size() > 1)
- fVerbose = params[1].get_bool();
+ if (request.params.size() > 1)
+ fVerbose = request.params[1].get_bool();
- uint256 hash = ParseHashV(params[0], "parameter 1");
+ uint256 hash = ParseHashV(request.params[0], "parameter 1");
LOCK(mempool.cs);
@@ -570,9 +570,9 @@ UniValue getmempooldescendants(const UniValue& params, bool fHelp)
}
}
-UniValue getmempoolentry(const UniValue& params, bool fHelp)
+UniValue getmempoolentry(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1) {
+ if (request.fHelp || request.params.size() != 1) {
throw runtime_error(
"getmempoolentry txid\n"
"\nReturns mempool data for given transaction\n"
@@ -588,7 +588,7 @@ UniValue getmempoolentry(const UniValue& params, bool fHelp)
);
}
- uint256 hash = ParseHashV(params[0], "parameter 1");
+ uint256 hash = ParseHashV(request.params[0], "parameter 1");
LOCK(mempool.cs);
@@ -603,9 +603,9 @@ UniValue getmempoolentry(const UniValue& params, bool fHelp)
return info;
}
-UniValue getblockhash(const UniValue& params, bool fHelp)
+UniValue getblockhash(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"getblockhash index\n"
"\nReturns hash of block in best-block-chain at index provided.\n"
@@ -620,7 +620,7 @@ UniValue getblockhash(const UniValue& params, bool fHelp)
LOCK(cs_main);
- int nHeight = params[0].get_int();
+ int nHeight = request.params[0].get_int();
if (nHeight < 0 || nHeight > chainActive.Height())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
@@ -628,9 +628,9 @@ UniValue getblockhash(const UniValue& params, bool fHelp)
return pblockindex->GetBlockHash().GetHex();
}
-UniValue getblockheader(const UniValue& params, bool fHelp)
+UniValue getblockheader(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"getblockheader \"hash\" ( verbose )\n"
"\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
@@ -664,12 +664,12 @@ UniValue getblockheader(const UniValue& params, bool fHelp)
LOCK(cs_main);
- std::string strHash = params[0].get_str();
+ std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
bool fVerbose = true;
- if (params.size() > 1)
- fVerbose = params[1].get_bool();
+ if (request.params.size() > 1)
+ fVerbose = request.params[1].get_bool();
if (mapBlockIndex.count(hash) == 0)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
@@ -687,9 +687,9 @@ UniValue getblockheader(const UniValue& params, bool fHelp)
return blockheaderToJSON(pblockindex);
}
-UniValue getblock(const UniValue& params, bool fHelp)
+UniValue getblock(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"getblock \"hash\" ( verbose )\n"
"\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
@@ -730,12 +730,12 @@ UniValue getblock(const UniValue& params, bool fHelp)
LOCK(cs_main);
- std::string strHash = params[0].get_str();
+ std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
bool fVerbose = true;
- if (params.size() > 1)
- fVerbose = params[1].get_bool();
+ if (request.params.size() > 1)
+ fVerbose = request.params[1].get_bool();
if (mapBlockIndex.count(hash) == 0)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
@@ -814,9 +814,9 @@ static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats)
return true;
}
-UniValue gettxoutsetinfo(const UniValue& params, bool fHelp)
+UniValue gettxoutsetinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"gettxoutsetinfo\n"
"\nReturns statistics about the unspent transaction output set.\n"
@@ -854,9 +854,9 @@ UniValue gettxoutsetinfo(const UniValue& params, bool fHelp)
return ret;
}
-UniValue gettxout(const UniValue& params, bool fHelp)
+UniValue gettxout(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 2 || params.size() > 3)
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
throw runtime_error(
"gettxout \"txid\" n ( includemempool )\n"
"\nReturns details about an unspent transaction output.\n"
@@ -896,12 +896,12 @@ UniValue gettxout(const UniValue& params, bool fHelp)
UniValue ret(UniValue::VOBJ);
- std::string strHash = params[0].get_str();
+ std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
- int n = params[1].get_int();
+ int n = request.params[1].get_int();
bool fMempool = true;
- if (params.size() > 2)
- fMempool = params[2].get_bool();
+ if (request.params.size() > 2)
+ fMempool = request.params[2].get_bool();
CCoins coins;
if (fMempool) {
@@ -934,11 +934,11 @@ UniValue gettxout(const UniValue& params, bool fHelp)
return ret;
}
-UniValue verifychain(const UniValue& params, bool fHelp)
+UniValue verifychain(const JSONRPCRequest& request)
{
int nCheckLevel = GetArg("-checklevel", DEFAULT_CHECKLEVEL);
int nCheckDepth = GetArg("-checkblocks", DEFAULT_CHECKBLOCKS);
- if (fHelp || params.size() > 2)
+ if (request.fHelp || request.params.size() > 2)
throw runtime_error(
"verifychain ( checklevel numblocks )\n"
"\nVerifies blockchain database.\n"
@@ -954,10 +954,10 @@ UniValue verifychain(const UniValue& params, bool fHelp)
LOCK(cs_main);
- if (params.size() > 0)
- nCheckLevel = params[0].get_int();
- if (params.size() > 1)
- nCheckDepth = params[1].get_int();
+ if (request.params.size() > 0)
+ nCheckLevel = request.params[0].get_int();
+ if (request.params.size() > 1)
+ nCheckDepth = request.params[1].get_int();
return CVerifyDB().VerifyDB(Params(), pcoinsTip, nCheckLevel, nCheckDepth);
}
@@ -1009,6 +1009,7 @@ static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Conse
}
rv.push_back(Pair("startTime", consensusParams.vDeployments[id].nStartTime));
rv.push_back(Pair("timeout", consensusParams.vDeployments[id].nTimeout));
+ rv.push_back(Pair("since", VersionBitsTipStateSinceHeight(consensusParams, id)));
return rv;
}
@@ -1021,9 +1022,9 @@ void BIP9SoftForkDescPushBack(UniValue& bip9_softforks, const std::string &name,
bip9_softforks.push_back(Pair(name, BIP9SoftForkDesc(consensusParams, id)));
}
-UniValue getblockchaininfo(const UniValue& params, bool fHelp)
+UniValue getblockchaininfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getblockchaininfo\n"
"Returns an object containing various state info regarding block chain processing.\n"
@@ -1053,7 +1054,8 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp)
" \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\"\n"
" \"bit\": xx, (numeric) the bit (0-28) in the block version field used to signal this softfork (only for \"started\" status)\n"
" \"startTime\": xx, (numeric) the minimum median time past of a block at which the bit gains its meaning\n"
- " \"timeout\": xx (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n"
+ " \"timeout\": xx, (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n"
+ " \"since\": xx (numeric) height of the first block to which the status applies\n"
" }\n"
" }\n"
"}\n"
@@ -1113,9 +1115,9 @@ struct CompareBlocksByHeight
}
};
-UniValue getchaintips(const UniValue& params, bool fHelp)
+UniValue getchaintips(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getchaintips\n"
"Return information about all known tips in the block tree,"
@@ -1229,9 +1231,9 @@ UniValue mempoolInfoToJSON()
return ret;
}
-UniValue getmempoolinfo(const UniValue& params, bool fHelp)
+UniValue getmempoolinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getmempoolinfo\n"
"\nReturns details on the active state of the TX memory pool.\n"
@@ -1251,9 +1253,47 @@ UniValue getmempoolinfo(const UniValue& params, bool fHelp)
return mempoolInfoToJSON();
}
-UniValue invalidateblock(const UniValue& params, bool fHelp)
+UniValue preciousblock(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
+ throw runtime_error(
+ "preciousblock \"hash\"\n"
+ "\nTreats a block as if it were received before others with the same work.\n"
+ "\nA later preciousblock call can override the effect of an earlier one.\n"
+ "\nThe effects of preciousblock are not retained across restarts.\n"
+ "\nArguments:\n"
+ "1. hash (string, required) the hash of the block to mark as precious\n"
+ "\nResult:\n"
+ "\nExamples:\n"
+ + HelpExampleCli("preciousblock", "\"blockhash\"")
+ + HelpExampleRpc("preciousblock", "\"blockhash\"")
+ );
+
+ std::string strHash = request.params[0].get_str();
+ uint256 hash(uint256S(strHash));
+ CBlockIndex* pblockindex;
+
+ {
+ LOCK(cs_main);
+ if (mapBlockIndex.count(hash) == 0)
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+
+ pblockindex = mapBlockIndex[hash];
+ }
+
+ CValidationState state;
+ PreciousBlock(state, Params(), pblockindex);
+
+ if (!state.IsValid()) {
+ throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
+ }
+
+ return NullUniValue;
+}
+
+UniValue invalidateblock(const JSONRPCRequest& request)
+{
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"invalidateblock \"hash\"\n"
"\nPermanently marks a block as invalid, as if it violated a consensus rule.\n"
@@ -1265,7 +1305,7 @@ UniValue invalidateblock(const UniValue& params, bool fHelp)
+ HelpExampleRpc("invalidateblock", "\"blockhash\"")
);
- std::string strHash = params[0].get_str();
+ std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
CValidationState state;
@@ -1279,7 +1319,7 @@ UniValue invalidateblock(const UniValue& params, bool fHelp)
}
if (state.IsValid()) {
- ActivateBestChain(state, Params(), NULL, g_connman.get());
+ ActivateBestChain(state, Params(), NULL);
}
if (!state.IsValid()) {
@@ -1289,9 +1329,9 @@ UniValue invalidateblock(const UniValue& params, bool fHelp)
return NullUniValue;
}
-UniValue reconsiderblock(const UniValue& params, bool fHelp)
+UniValue reconsiderblock(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"reconsiderblock \"hash\"\n"
"\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n"
@@ -1304,7 +1344,7 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp)
+ HelpExampleRpc("reconsiderblock", "\"blockhash\"")
);
- std::string strHash = params[0].get_str();
+ std::string strHash = request.params[0].get_str();
uint256 hash(uint256S(strHash));
{
@@ -1317,7 +1357,7 @@ UniValue reconsiderblock(const UniValue& params, bool fHelp)
}
CValidationState state;
- ActivateBestChain(state, Params(), NULL, g_connman.get());
+ ActivateBestChain(state, Params(), NULL);
if (!state.IsValid()) {
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
@@ -1346,6 +1386,8 @@ static const CRPCCommand commands[] =
{ "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true },
{ "blockchain", "verifychain", &verifychain, true },
+ { "blockchain", "preciousblock", &preciousblock, true },
+
/* Not shown in help */
{ "hidden", "invalidateblock", &invalidateblock, true },
{ "hidden", "reconsiderblock", &reconsiderblock, true },
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 6b13aa5bab..d509dd691f 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -22,6 +22,7 @@
#include "utilstrencodings.h"
#include "validationinterface.h"
+#include <memory>
#include <stdint.h>
#include <boost/assign/list_of.hpp>
@@ -73,9 +74,9 @@ UniValue GetNetworkHashPS(int lookup, int height) {
return workDiff.getdouble() / timeDiff;
}
-UniValue getnetworkhashps(const UniValue& params, bool fHelp)
+UniValue getnetworkhashps(const JSONRPCRequest& request)
{
- if (fHelp || params.size() > 2)
+ if (request.fHelp || request.params.size() > 2)
throw runtime_error(
"getnetworkhashps ( blocks height )\n"
"\nReturns the estimated network hashes per second based on the last n blocks.\n"
@@ -92,7 +93,7 @@ UniValue getnetworkhashps(const UniValue& params, bool fHelp)
);
LOCK(cs_main);
- return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1);
+ return GetNetworkHashPS(request.params.size() > 0 ? request.params[0].get_int() : 120, request.params.size() > 1 ? request.params[1].get_int() : -1);
}
UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript)
@@ -131,7 +132,7 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG
continue;
}
CValidationState state;
- if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL, g_connman.get()))
+ if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL))
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex());
@@ -145,9 +146,9 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG
return blockHashes;
}
-UniValue generate(const UniValue& params, bool fHelp)
+UniValue generate(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"generate numblocks ( maxtries )\n"
"\nMine up to numblocks blocks immediately (before the RPC call returns)\n"
@@ -161,10 +162,10 @@ UniValue generate(const UniValue& params, bool fHelp)
+ HelpExampleCli("generate", "11")
);
- int nGenerate = params[0].get_int();
+ int nGenerate = request.params[0].get_int();
uint64_t nMaxTries = 1000000;
- if (params.size() > 1) {
- nMaxTries = params[1].get_int();
+ if (request.params.size() > 1) {
+ nMaxTries = request.params[1].get_int();
}
boost::shared_ptr<CReserveScript> coinbaseScript;
@@ -181,9 +182,9 @@ UniValue generate(const UniValue& params, bool fHelp)
return generateBlocks(coinbaseScript, nGenerate, nMaxTries, true);
}
-UniValue generatetoaddress(const UniValue& params, bool fHelp)
+UniValue generatetoaddress(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 2 || params.size() > 3)
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
throw runtime_error(
"generatetoaddress numblocks address (maxtries)\n"
"\nMine blocks immediately to a specified address (before the RPC call returns)\n"
@@ -198,13 +199,13 @@ UniValue generatetoaddress(const UniValue& params, bool fHelp)
+ HelpExampleCli("generatetoaddress", "11 \"myaddress\"")
);
- int nGenerate = params[0].get_int();
+ int nGenerate = request.params[0].get_int();
uint64_t nMaxTries = 1000000;
- if (params.size() > 2) {
- nMaxTries = params[2].get_int();
+ if (request.params.size() > 2) {
+ nMaxTries = request.params[2].get_int();
}
- CBitcoinAddress address(params[1].get_str());
+ CBitcoinAddress address(request.params[1].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
@@ -214,9 +215,9 @@ UniValue generatetoaddress(const UniValue& params, bool fHelp)
return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false);
}
-UniValue getmininginfo(const UniValue& params, bool fHelp)
+UniValue getmininginfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getmininginfo\n"
"\nReturns a json object containing mining-related information."
@@ -230,7 +231,6 @@ UniValue getmininginfo(const UniValue& params, bool fHelp)
" \"errors\": \"...\" (string) Current errors\n"
" \"networkhashps\": nnn, (numeric) The network hashes per second\n"
" \"pooledtx\": n (numeric) The size of the mem pool\n"
- " \"testnet\": true|false (boolean) If using testnet or not\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
"}\n"
"\nExamples:\n"
@@ -248,18 +248,17 @@ UniValue getmininginfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
- obj.push_back(Pair("networkhashps", getnetworkhashps(params, false)));
+ obj.push_back(Pair("networkhashps", getnetworkhashps(request)));
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
- obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
obj.push_back(Pair("chain", Params().NetworkIDString()));
return obj;
}
// NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
-UniValue prioritisetransaction(const UniValue& params, bool fHelp)
+UniValue prioritisetransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 3)
+ if (request.fHelp || request.params.size() != 3)
throw runtime_error(
"prioritisetransaction <txid> <priority delta> <fee delta>\n"
"Accepts the transaction into mined blocks at a higher (or lower) priority\n"
@@ -280,10 +279,10 @@ UniValue prioritisetransaction(const UniValue& params, bool fHelp)
LOCK(cs_main);
- uint256 hash = ParseHashStr(params[0].get_str(), "txid");
- CAmount nAmount = params[2].get_int64();
+ uint256 hash = ParseHashStr(request.params[0].get_str(), "txid");
+ CAmount nAmount = request.params[2].get_int64();
- mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), nAmount);
+ mempool.PrioritiseTransaction(hash, request.params[0].get_str(), request.params[1].get_real(), nAmount);
return true;
}
@@ -316,71 +315,77 @@ std::string gbt_vb_name(const Consensus::DeploymentPos pos) {
return s;
}
-UniValue getblocktemplate(const UniValue& params, bool fHelp)
+UniValue getblocktemplate(const JSONRPCRequest& request)
{
- if (fHelp || params.size() > 1)
+ if (request.fHelp || request.params.size() > 1)
throw runtime_error(
- "getblocktemplate ( \"jsonrequestobject\" )\n"
+ "getblocktemplate ( TemplateRequest )\n"
"\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n"
"It returns data needed to construct a block to work on.\n"
- "For full specification, see BIPs 22 and 9:\n"
+ "For full specification, see BIPs 22, 23, 9, and 145:\n"
" https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki\n"
+ " https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki\n"
" https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n"
+ " https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n"
"\nArguments:\n"
- "1. \"jsonrequestobject\" (string, optional) A json object in the following spec\n"
+ "1. TemplateRequest (json object, optional) A json object in the following spec\n"
" {\n"
- " \"mode\":\"template\" (string, optional) This must be set to \"template\" or omitted\n"
- " \"capabilities\":[ (array, optional) A list of strings\n"
- " \"support\" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'\n"
+ " \"mode\":\"template\" (string, optional) This must be set to \"template\", \"proposal\" (see BIP 23), or omitted\n"
+ " \"capabilities\":[ (array, optional) A list of strings\n"
+ " \"support\" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'\n"
" ,...\n"
- " ]\n"
+ " ],\n"
+ " \"rules\":[ (array, optional) A list of strings\n"
+ " \"support\" (string) client side supported softfork deployment\n"
+ " ,...\n"
+ " ]\n"
" }\n"
"\n"
"\nResult:\n"
"{\n"
- " \"version\" : n, (numeric) The block version\n"
+ " \"version\" : n, (numeric) The preferred block version\n"
" \"rules\" : [ \"rulename\", ... ], (array of strings) specific block rules that are to be enforced\n"
" \"vbavailable\" : { (json object) set of pending, supported versionbit (BIP 9) softfork deployments\n"
- " \"rulename\" : bitnumber (numeric) identifies the bit number as indicating acceptance and readiness for the named softfork rule\n"
+ " \"rulename\" : bitnumber (numeric) identifies the bit number as indicating acceptance and readiness for the named softfork rule\n"
" ,...\n"
" },\n"
" \"vbrequired\" : n, (numeric) bit mask of versionbits the server requires set in submissions\n"
- " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n"
+ " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n"
" \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n"
" {\n"
- " \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n"
- " \"txid\" : \"xxxx\", (string) transaction id encoded in little-endian hexadecimal\n"
- " \"hash\" : \"xxxx\", (string) hash encoded in little-endian hexadecimal (including witness data)\n"
- " \"depends\" : [ (array) array of numbers \n"
- " n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n"
+ " \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n"
+ " \"txid\" : \"xxxx\", (string) transaction id encoded in little-endian hexadecimal\n"
+ " \"hash\" : \"xxxx\", (string) hash encoded in little-endian hexadecimal (including witness data)\n"
+ " \"depends\" : [ (array) array of numbers \n"
+ " n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n"
" ,...\n"
" ],\n"
- " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in Satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n"
- " \"sigops\" : n, (numeric) total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero\n"
- " \"weight\" : n, (numeric) total transaction weight, as counted for purposes of block limits\n"
- " \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n"
+ " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in Satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n"
+ " \"sigops\" : n, (numeric) total SigOps cost, as counted for purposes of block limits; if key is not present, sigop cost is unknown and clients MUST NOT assume it is zero\n"
+ " \"weight\" : n, (numeric) total transaction weight, as counted for purposes of block limits\n"
+ " \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n"
" }\n"
" ,...\n"
" ],\n"
- " \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n"
- " \"flags\" : \"flags\" (string) \n"
+ " \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n"
+ " \"flags\" : \"xx\" (string) key name is to be ignored, and value included in scriptSig\n"
" },\n"
- " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in Satoshis)\n"
- " \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n"
- " \"target\" : \"xxxx\", (string) The hash target\n"
- " \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n"
- " \"mutable\" : [ (array of string) list of ways the block template may be changed \n"
- " \"value\" (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'\n"
+ " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in Satoshis)\n"
+ " \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n"
+ " \"target\" : \"xxxx\", (string) The hash target\n"
+ " \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n"
+ " \"mutable\" : [ (array of string) list of ways the block template may be changed \n"
+ " \"value\" (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'\n"
" ,...\n"
" ],\n"
- " \"noncerange\" : \"00000000ffffffff\", (string) A range of valid nonces\n"
- " \"sigoplimit\" : n, (numeric) cost limit of sigops in blocks\n"
+ " \"noncerange\" : \"00000000ffffffff\",(string) A range of valid nonces\n"
+ " \"sigoplimit\" : n, (numeric) limit of sigops in blocks\n"
" \"sizelimit\" : n, (numeric) limit of block size\n"
" \"weightlimit\" : n, (numeric) limit of block weight\n"
" \"curtime\" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT)\n"
- " \"bits\" : \"xxx\", (string) compressed target of next block\n"
+ " \"bits\" : \"xxxxxxxx\", (string) compressed target of next block\n"
" \"height\" : n (numeric) The height of the next block\n"
"}\n"
@@ -395,9 +400,9 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
UniValue lpval = NullUniValue;
std::set<std::string> setClientRules;
int64_t nMaxVersionPreVB = -1;
- if (params.size() > 0)
+ if (request.params.size() > 0)
{
- const UniValue& oparam = params[0].get_obj();
+ const UniValue& oparam = request.params[0].get_obj();
const UniValue& modeval = find_value(oparam, "mode");
if (modeval.isStr())
strMode = modeval.get_str();
@@ -517,12 +522,12 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
// Update block
static CBlockIndex* pindexPrev;
static int64_t nStart;
- static CBlockTemplate* pblocktemplate;
+ static std::unique_ptr<CBlockTemplate> pblocktemplate;
if (pindexPrev != chainActive.Tip() ||
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5))
{
// Clear pindexPrev so future calls make a new block, despite any failures from here on
- pindexPrev = NULL;
+ pindexPrev = nullptr;
// Store the pindexBest used before CreateNewBlock, to avoid races
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
@@ -530,11 +535,6 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
nStart = GetTime();
// Create new block
- if(pblocktemplate)
- {
- delete pblocktemplate;
- pblocktemplate = NULL;
- }
CScript scriptDummy = CScript() << OP_TRUE;
pblocktemplate = BlockAssembler(Params()).CreateNewBlock(scriptDummy);
if (!pblocktemplate)
@@ -705,9 +705,9 @@ protected:
};
};
-UniValue submitblock(const UniValue& params, bool fHelp)
+UniValue submitblock(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"submitblock \"hexdata\" ( \"jsonparametersobject\" )\n"
"\nAttempts to submit new block to network.\n"
@@ -727,7 +727,7 @@ UniValue submitblock(const UniValue& params, bool fHelp)
);
CBlock block;
- if (!DecodeHexBlk(block, params[0].get_str()))
+ if (!DecodeHexBlk(block, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
uint256 hash = block.GetHash();
@@ -757,7 +757,7 @@ UniValue submitblock(const UniValue& params, bool fHelp)
CValidationState state;
submitblock_StateCatcher sc(block.GetHash());
RegisterValidationInterface(&sc);
- bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL, g_connman.get());
+ bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL);
UnregisterValidationInterface(&sc);
if (fBlockPresent)
{
@@ -774,9 +774,9 @@ UniValue submitblock(const UniValue& params, bool fHelp)
return BIP22ValidationResult(state);
}
-UniValue estimatefee(const UniValue& params, bool fHelp)
+UniValue estimatefee(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"estimatefee nblocks\n"
"\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
@@ -792,9 +792,9 @@ UniValue estimatefee(const UniValue& params, bool fHelp)
+ HelpExampleCli("estimatefee", "6")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
- int nBlocks = params[0].get_int();
+ int nBlocks = request.params[0].get_int();
if (nBlocks < 1)
nBlocks = 1;
@@ -805,9 +805,9 @@ UniValue estimatefee(const UniValue& params, bool fHelp)
return ValueFromAmount(feeRate.GetFeePerK());
}
-UniValue estimatepriority(const UniValue& params, bool fHelp)
+UniValue estimatepriority(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"estimatepriority nblocks\n"
"\nEstimates the approximate priority a zero-fee transaction needs to begin\n"
@@ -823,18 +823,18 @@ UniValue estimatepriority(const UniValue& params, bool fHelp)
+ HelpExampleCli("estimatepriority", "6")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
- int nBlocks = params[0].get_int();
+ int nBlocks = request.params[0].get_int();
if (nBlocks < 1)
nBlocks = 1;
return mempool.estimatePriority(nBlocks);
}
-UniValue estimatesmartfee(const UniValue& params, bool fHelp)
+UniValue estimatesmartfee(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"estimatesmartfee nblocks\n"
"\nWARNING: This interface is unstable and may disappear or change!\n"
@@ -856,9 +856,9 @@ UniValue estimatesmartfee(const UniValue& params, bool fHelp)
+ HelpExampleCli("estimatesmartfee", "6")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
- int nBlocks = params[0].get_int();
+ int nBlocks = request.params[0].get_int();
UniValue result(UniValue::VOBJ);
int answerFound;
@@ -868,9 +868,9 @@ UniValue estimatesmartfee(const UniValue& params, bool fHelp)
return result;
}
-UniValue estimatesmartpriority(const UniValue& params, bool fHelp)
+UniValue estimatesmartpriority(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"estimatesmartpriority nblocks\n"
"\nWARNING: This interface is unstable and may disappear or change!\n"
@@ -892,9 +892,9 @@ UniValue estimatesmartpriority(const UniValue& params, bool fHelp)
+ HelpExampleCli("estimatesmartpriority", "6")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
- int nBlocks = params[0].get_int();
+ int nBlocks = request.params[0].get_int();
UniValue result(UniValue::VOBJ);
int answerFound;
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index f0b7e0a07c..eaef4856b3 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -39,9 +39,9 @@ using namespace std;
*
* Or alternatively, create a specific query method for the information.
**/
-UniValue getinfo(const UniValue& params, bool fHelp)
+UniValue getinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getinfo\n"
"\nDEPRECATED. Returns an object containing various state info.\n"
@@ -93,7 +93,7 @@ UniValue getinfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("connections", (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL)));
obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
- obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
+ obj.push_back(Pair("testnet", Params().NetworkIDString() == CBaseChainParams::TESTNET));
#ifdef ENABLE_WALLET
if (pwalletMain) {
obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
@@ -148,9 +148,9 @@ public:
};
#endif
-UniValue validateaddress(const UniValue& params, bool fHelp)
+UniValue validateaddress(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"validateaddress \"bitcoinaddress\"\n"
"\nReturn information about the given bitcoin address.\n"
@@ -181,7 +181,7 @@ UniValue validateaddress(const UniValue& params, bool fHelp)
LOCK(cs_main);
#endif
- CBitcoinAddress address(params[0].get_str());
+ CBitcoinAddress address(request.params[0].get_str());
bool isValid = address.IsValid();
UniValue ret(UniValue::VOBJ);
@@ -278,9 +278,9 @@ CScript _createmultisig_redeemScript(const UniValue& params)
return result;
}
-UniValue createmultisig(const UniValue& params, bool fHelp)
+UniValue createmultisig(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 2 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 2)
{
string msg = "createmultisig nrequired [\"key\",...]\n"
"\nCreates a multi-signature address with n signature of m keys required.\n"
@@ -310,7 +310,7 @@ UniValue createmultisig(const UniValue& params, bool fHelp)
}
// Construct using pay-to-script-hash:
- CScript inner = _createmultisig_redeemScript(params);
+ CScript inner = _createmultisig_redeemScript(request.params);
CScriptID innerID(inner);
CBitcoinAddress address(innerID);
@@ -321,9 +321,9 @@ UniValue createmultisig(const UniValue& params, bool fHelp)
return result;
}
-UniValue verifymessage(const UniValue& params, bool fHelp)
+UniValue verifymessage(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 3)
+ if (request.fHelp || request.params.size() != 3)
throw runtime_error(
"verifymessage \"bitcoinaddress\" \"signature\" \"message\"\n"
"\nVerify a signed message\n"
@@ -346,9 +346,9 @@ UniValue verifymessage(const UniValue& params, bool fHelp)
LOCK(cs_main);
- string strAddress = params[0].get_str();
- string strSign = params[1].get_str();
- string strMessage = params[2].get_str();
+ string strAddress = request.params[0].get_str();
+ string strSign = request.params[1].get_str();
+ string strMessage = request.params[2].get_str();
CBitcoinAddress addr(strAddress);
if (!addr.IsValid())
@@ -375,9 +375,9 @@ UniValue verifymessage(const UniValue& params, bool fHelp)
return (pubkey.GetID() == keyID);
}
-UniValue signmessagewithprivkey(const UniValue& params, bool fHelp)
+UniValue signmessagewithprivkey(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 2)
+ if (request.fHelp || request.params.size() != 2)
throw runtime_error(
"signmessagewithprivkey \"privkey\" \"message\"\n"
"\nSign a message with the private key of an address\n"
@@ -395,8 +395,8 @@ UniValue signmessagewithprivkey(const UniValue& params, bool fHelp)
+ HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
);
- string strPrivkey = params[0].get_str();
- string strMessage = params[1].get_str();
+ string strPrivkey = request.params[0].get_str();
+ string strMessage = request.params[1].get_str();
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(strPrivkey);
@@ -417,9 +417,9 @@ UniValue signmessagewithprivkey(const UniValue& params, bool fHelp)
return EncodeBase64(&vchSig[0], vchSig.size());
}
-UniValue setmocktime(const UniValue& params, bool fHelp)
+UniValue setmocktime(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"setmocktime timestamp\n"
"\nSet the local time to given timestamp (-regtest only)\n"
@@ -437,8 +437,8 @@ UniValue setmocktime(const UniValue& params, bool fHelp)
// in a long time.
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
- SetMockTime(params[0].get_int64());
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM));
+ SetMockTime(request.params[0].get_int64());
uint64_t t = GetTime();
if(g_connman) {
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index b011029f51..2b43f08f0b 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -23,9 +23,9 @@
using namespace std;
-UniValue getconnectioncount(const UniValue& params, bool fHelp)
+UniValue getconnectioncount(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getconnectioncount\n"
"\nReturns the number of connections to other nodes.\n"
@@ -42,9 +42,9 @@ UniValue getconnectioncount(const UniValue& params, bool fHelp)
return (int)g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL);
}
-UniValue ping(const UniValue& params, bool fHelp)
+UniValue ping(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"ping\n"
"\nRequests that a ping be sent to all other nodes, to measure ping time.\n"
@@ -65,9 +65,9 @@ UniValue ping(const UniValue& params, bool fHelp)
return NullUniValue;
}
-UniValue getpeerinfo(const UniValue& params, bool fHelp)
+UniValue getpeerinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getpeerinfo\n"
"\nReturns data about each connected network node as a json array of objects.\n"
@@ -141,8 +141,8 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
obj.push_back(Pair("timeoffset", stats.nTimeOffset));
if (stats.dPingTime > 0.0)
obj.push_back(Pair("pingtime", stats.dPingTime));
- if (stats.dPingMin < std::numeric_limits<int64_t>::max()/1e6)
- obj.push_back(Pair("minping", stats.dPingMin));
+ if (stats.dMinPing < std::numeric_limits<int64_t>::max()/1e6)
+ obj.push_back(Pair("minping", stats.dMinPing));
if (stats.dPingWait > 0.0)
obj.push_back(Pair("pingwait", stats.dPingWait));
obj.push_back(Pair("version", stats.nVersion));
@@ -184,12 +184,12 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp)
return ret;
}
-UniValue addnode(const UniValue& params, bool fHelp)
+UniValue addnode(const JSONRPCRequest& request)
{
string strCommand;
- if (params.size() == 2)
- strCommand = params[1].get_str();
- if (fHelp || params.size() != 2 ||
+ if (request.params.size() == 2)
+ strCommand = request.params[1].get_str();
+ if (request.fHelp || request.params.size() != 2 ||
(strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
throw runtime_error(
"addnode \"node\" \"add|remove|onetry\"\n"
@@ -206,7 +206,7 @@ UniValue addnode(const UniValue& params, bool fHelp)
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- string strNode = params[0].get_str();
+ string strNode = request.params[0].get_str();
if (strCommand == "onetry")
{
@@ -229,9 +229,9 @@ UniValue addnode(const UniValue& params, bool fHelp)
return NullUniValue;
}
-UniValue disconnectnode(const UniValue& params, bool fHelp)
+UniValue disconnectnode(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"disconnectnode \"node\" \n"
"\nImmediately disconnects from the specified node.\n"
@@ -245,16 +245,16 @@ UniValue disconnectnode(const UniValue& params, bool fHelp)
if(!g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- bool ret = g_connman->DisconnectNode(params[0].get_str());
+ bool ret = g_connman->DisconnectNode(request.params[0].get_str());
if (!ret)
throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
return NullUniValue;
}
-UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
+UniValue getaddednodeinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() > 1)
+ if (request.fHelp || request.params.size() > 1)
throw runtime_error(
"getaddednodeinfo ( \"node\" )\n"
"\nReturns information about the given added node, or all added nodes\n"
@@ -286,10 +286,10 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
std::vector<AddedNodeInfo> vInfo = g_connman->GetAddedNodeInfo();
- if (params.size() == 1) {
+ if (request.params.size() == 1) {
bool found = false;
for (const AddedNodeInfo& info : vInfo) {
- if (info.strAddedNode == params[0].get_str()) {
+ if (info.strAddedNode == request.params[0].get_str()) {
vInfo.assign(1, info);
found = true;
break;
@@ -320,9 +320,9 @@ UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
return ret;
}
-UniValue getnettotals(const UniValue& params, bool fHelp)
+UniValue getnettotals(const JSONRPCRequest& request)
{
- if (fHelp || params.size() > 0)
+ if (request.fHelp || request.params.size() > 0)
throw runtime_error(
"getnettotals\n"
"\nReturns information about network traffic, including bytes in, bytes out,\n"
@@ -386,9 +386,9 @@ static UniValue GetNetworksInfo()
return networks;
}
-UniValue getnetworkinfo(const UniValue& params, bool fHelp)
+UniValue getnetworkinfo(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getnetworkinfo\n"
"Returns an object containing various state info regarding P2P networking.\n"
@@ -456,12 +456,12 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp)
return obj;
}
-UniValue setban(const UniValue& params, bool fHelp)
+UniValue setban(const JSONRPCRequest& request)
{
string strCommand;
- if (params.size() >= 2)
- strCommand = params[1].get_str();
- if (fHelp || params.size() < 2 ||
+ if (request.params.size() >= 2)
+ strCommand = request.params[1].get_str();
+ if (request.fHelp || request.params.size() < 2 ||
(strCommand != "add" && strCommand != "remove"))
throw runtime_error(
"setban \"ip(/netmask)\" \"add|remove\" (bantime) (absolute)\n"
@@ -483,16 +483,16 @@ UniValue setban(const UniValue& params, bool fHelp)
CNetAddr netAddr;
bool isSubnet = false;
- if (params[0].get_str().find("/") != string::npos)
+ if (request.params[0].get_str().find("/") != string::npos)
isSubnet = true;
if (!isSubnet) {
CNetAddr resolved;
- LookupHost(params[0].get_str().c_str(), resolved, false);
+ LookupHost(request.params[0].get_str().c_str(), resolved, false);
netAddr = resolved;
}
else
- LookupSubNet(params[0].get_str().c_str(), subNet);
+ LookupSubNet(request.params[0].get_str().c_str(), subNet);
if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) )
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Invalid IP/Subnet");
@@ -503,11 +503,11 @@ UniValue setban(const UniValue& params, bool fHelp)
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();
+ if (request.params.size() >= 3 && !request.params[2].isNull())
+ banTime = request.params[2].get_int64();
bool absolute = false;
- if (params.size() == 4 && params[3].isTrue())
+ if (request.params.size() == 4 && request.params[3].isTrue())
absolute = true;
isSubnet ? g_connman->Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : g_connman->Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
@@ -520,9 +520,9 @@ UniValue setban(const UniValue& params, bool fHelp)
return NullUniValue;
}
-UniValue listbanned(const UniValue& params, bool fHelp)
+UniValue listbanned(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"listbanned\n"
"\nList all banned IPs/Subnets.\n"
@@ -553,9 +553,9 @@ UniValue listbanned(const UniValue& params, bool fHelp)
return bannedAddresses;
}
-UniValue clearbanned(const UniValue& params, bool fHelp)
+UniValue clearbanned(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"clearbanned\n"
"\nClear all banned IPs.\n"
diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp
index bb885bb5a6..ec186f4fc5 100644
--- a/src/rpc/protocol.cpp
+++ b/src/rpc/protocol.cpp
@@ -26,13 +26,13 @@ using namespace std;
* 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
*/
-string JSONRPCRequest(const string& strMethod, const UniValue& params, const UniValue& id)
+UniValue JSONRPCRequestObj(const string& strMethod, const UniValue& params, const UniValue& id)
{
UniValue request(UniValue::VOBJ);
request.push_back(Pair("method", strMethod));
request.push_back(Pair("params", params));
request.push_back(Pair("id", id));
- return request.write() + "\n";
+ return request;
}
UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id)
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index 1d2ef0e41e..c74fa0070f 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -77,7 +77,7 @@ enum RPCErrorCode
RPC_WALLET_ALREADY_UNLOCKED = -17, //!< Wallet is already unlocked
};
-std::string JSONRPCRequest(const std::string& strMethod, const UniValue& params, const UniValue& id);
+UniValue JSONRPCRequestObj(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);
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index d2ad0a52b7..0656a61755 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -126,9 +126,9 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
}
}
-UniValue getrawtransaction(const UniValue& params, bool fHelp)
+UniValue getrawtransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"getrawtransaction \"txid\" ( verbose )\n"
"\nNOTE: By default this function only works sometimes. This is when the tx is in the mempool\n"
@@ -198,11 +198,11 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
LOCK(cs_main);
- uint256 hash = ParseHashV(params[0], "parameter 1");
+ uint256 hash = ParseHashV(request.params[0], "parameter 1");
bool fVerbose = false;
- if (params.size() > 1)
- fVerbose = (params[1].get_int() != 0);
+ if (request.params.size() > 1)
+ fVerbose = (request.params[1].get_int() != 0);
CTransaction tx;
uint256 hashBlock;
@@ -220,9 +220,9 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
return result;
}
-UniValue gettxoutproof(const UniValue& params, bool fHelp)
+UniValue gettxoutproof(const JSONRPCRequest& request)
{
- if (fHelp || (params.size() != 1 && params.size() != 2))
+ if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2))
throw runtime_error(
"gettxoutproof [\"txid\",...] ( blockhash )\n"
"\nReturns a hex-encoded proof that \"txid\" was included in a block.\n"
@@ -244,7 +244,7 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp)
set<uint256> setTxids;
uint256 oneTxid;
- UniValue txids = params[0].get_array();
+ UniValue txids = request.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()))
@@ -261,9 +261,9 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp)
CBlockIndex* pblockindex = NULL;
uint256 hashBlock;
- if (params.size() > 1)
+ if (request.params.size() > 1)
{
- hashBlock = uint256S(params[1].get_str());
+ hashBlock = uint256S(request.params[1].get_str());
if (!mapBlockIndex.count(hashBlock))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
pblockindex = mapBlockIndex[hashBlock];
@@ -301,9 +301,9 @@ UniValue gettxoutproof(const UniValue& params, bool fHelp)
return strHex;
}
-UniValue verifytxoutproof(const UniValue& params, bool fHelp)
+UniValue verifytxoutproof(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"verifytxoutproof \"proof\"\n"
"\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n"
@@ -314,7 +314,7 @@ UniValue verifytxoutproof(const UniValue& params, bool fHelp)
"[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof is invalid\n"
);
- CDataStream ssMB(ParseHexV(params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
+ CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
CMerkleBlock merkleBlock;
ssMB >> merkleBlock;
@@ -335,9 +335,9 @@ UniValue verifytxoutproof(const UniValue& params, bool fHelp)
return res;
}
-UniValue createrawtransaction(const UniValue& params, bool fHelp)
+UniValue createrawtransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 2 || params.size() > 3)
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
throw runtime_error(
"createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...} ( locktime )\n"
"\nCreate a transaction spending the given inputs and creating new outputs.\n"
@@ -373,17 +373,17 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"data\\\":\\\"00010203\\\"}\"")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)(UniValue::VNUM), true);
- if (params[0].isNull() || params[1].isNull())
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)(UniValue::VNUM), true);
+ if (request.params[0].isNull() || request.params[1].isNull())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, arguments 1 and 2 must be non-null");
- UniValue inputs = params[0].get_array();
- UniValue sendTo = params[1].get_obj();
+ UniValue inputs = request.params[0].get_array();
+ UniValue sendTo = request.params[1].get_obj();
CMutableTransaction rawTx;
- if (params.size() > 2 && !params[2].isNull()) {
- int64_t nLockTime = params[2].get_int64();
+ if (request.params.size() > 2 && !request.params[2].isNull()) {
+ int64_t nLockTime = request.params[2].get_int64();
if (nLockTime < 0 || nLockTime > std::numeric_limits<uint32_t>::max())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, locktime out of range");
rawTx.nLockTime = nLockTime;
@@ -448,9 +448,9 @@ UniValue createrawtransaction(const UniValue& params, bool fHelp)
return EncodeHexTx(rawTx);
}
-UniValue decoderawtransaction(const UniValue& params, bool fHelp)
+UniValue decoderawtransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"decoderawtransaction \"hexstring\"\n"
"\nReturn a JSON object representing the serialized, hex-encoded transaction.\n"
@@ -504,11 +504,11 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp)
);
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR));
CTransaction tx;
- if (!DecodeHexTx(tx, params[0].get_str(), true))
+ if (!DecodeHexTx(tx, request.params[0].get_str(), true))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
UniValue result(UniValue::VOBJ);
@@ -517,9 +517,9 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp)
return result;
}
-UniValue decodescript(const UniValue& params, bool fHelp)
+UniValue decodescript(const JSONRPCRequest& request)
{
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"decodescript \"hex\"\n"
"\nDecode a hex-encoded script.\n"
@@ -535,26 +535,34 @@ UniValue decodescript(const UniValue& params, bool fHelp)
" \"address\" (string) bitcoin address\n"
" ,...\n"
" ],\n"
- " \"p2sh\",\"address\" (string) script address\n"
+ " \"p2sh\",\"address\" (string) address of P2SH script wrapping this redeem script (not returned if the script is already a P2SH).\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("decodescript", "\"hexstring\"")
+ HelpExampleRpc("decodescript", "\"hexstring\"")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR));
UniValue r(UniValue::VOBJ);
CScript script;
- if (params[0].get_str().size() > 0){
- vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
+ if (request.params[0].get_str().size() > 0){
+ vector<unsigned char> scriptData(ParseHexV(request.params[0], "argument"));
script = CScript(scriptData.begin(), scriptData.end());
} else {
// Empty scripts are valid
}
ScriptPubKeyToJSON(script, r, false);
- r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString()));
+ UniValue type;
+ type = find_value(r, "type");
+
+ if (type.isStr() && type.get_str() != "scripthash") {
+ // P2SH cannot be wrapped in a P2SH. If this script is already a P2SH,
+ // don't return the address for a P2SH of the P2SH.
+ r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString()));
+ }
+
return r;
}
@@ -570,9 +578,9 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::
vErrorsRet.push_back(entry);
}
-UniValue signrawtransaction(const UniValue& params, bool fHelp)
+UniValue signrawtransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 4)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
throw runtime_error(
"signrawtransaction \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype )\n"
"\nSign inputs for raw transaction (serialized, hex-encoded).\n"
@@ -636,9 +644,9 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
#else
LOCK(cs_main);
#endif
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true);
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true);
- vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
+ vector<unsigned char> txData(ParseHexV(request.params[0], "argument 1"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
vector<CMutableTransaction> txVariants;
while (!ssData.empty()) {
@@ -679,9 +687,9 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
- if (params.size() > 2 && !params[2].isNull()) {
+ if (request.params.size() > 2 && !request.params[2].isNull()) {
fGivenKeys = true;
- UniValue keys = params[2].get_array();
+ UniValue keys = request.params[2].get_array();
for (unsigned int idx = 0; idx < keys.size(); idx++) {
UniValue k = keys[idx];
CBitcoinSecret vchSecret;
@@ -700,8 +708,8 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
#endif
// Add previous txouts given in the RPC call:
- if (params.size() > 1 && !params[1].isNull()) {
- UniValue prevTxs = params[1].get_array();
+ if (request.params.size() > 1 && !request.params[1].isNull()) {
+ UniValue prevTxs = request.params[1].get_array();
for (unsigned int idx = 0; idx < prevTxs.size(); idx++) {
const UniValue& p = prevTxs[idx];
if (!p.isObject())
@@ -769,7 +777,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
#endif
int nHashType = SIGHASH_ALL;
- if (params.size() > 3 && !params[3].isNull()) {
+ if (request.params.size() > 3 && !request.params[3].isNull()) {
static map<string, int> mapSigHashValues =
boost::assign::map_list_of
(string("ALL"), int(SIGHASH_ALL))
@@ -779,7 +787,7 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
(string("SINGLE"), int(SIGHASH_SINGLE))
(string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
;
- string strHashType = params[3].get_str();
+ string strHashType = request.params[3].get_str();
if (mapSigHashValues.count(strHashType))
nHashType = mapSigHashValues[strHashType];
else
@@ -834,9 +842,9 @@ UniValue signrawtransaction(const UniValue& params, bool fHelp)
return result;
}
-UniValue sendrawtransaction(const UniValue& params, bool fHelp)
+UniValue sendrawtransaction(const JSONRPCRequest& request)
{
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"sendrawtransaction \"hexstring\" ( allowhighfees )\n"
"\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n"
@@ -858,16 +866,17 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
);
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL));
// parse hex string from parameter
CTransaction tx;
- if (!DecodeHexTx(tx, params[0].get_str()))
+ if (!DecodeHexTx(tx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
uint256 hashTx = tx.GetHash();
+ bool fLimitFree = false;
CAmount nMaxRawTxFee = maxTxFee;
- if (params.size() > 1 && params[1].get_bool())
+ if (request.params.size() > 1 && request.params[1].get_bool())
nMaxRawTxFee = 0;
CCoinsViewCache &view = *pcoinsTip;
@@ -878,7 +887,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp)
// push to local node and sync with wallets
CValidationState state;
bool fMissingInputs;
- if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, false, nMaxRawTxFee)) {
+ if (!AcceptToMemoryPool(mempool, state, tx, fLimitFree, &fMissingInputs, false, nMaxRawTxFee)) {
if (state.IsInvalid()) {
throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason()));
} else {
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index 5fb97f7496..29d0bee1b2 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -195,10 +195,11 @@ std::string CRPCTable::help(const std::string& strCommand) const
continue;
try
{
- UniValue params;
+ JSONRPCRequest jreq;
+ jreq.fHelp = true;
rpcfn_type pfn = pcmd->actor;
if (setDone.insert(pfn).second)
- (*pfn)(params, true);
+ (*pfn)(jreq);
}
catch (const std::exception& e)
{
@@ -228,9 +229,9 @@ std::string CRPCTable::help(const std::string& strCommand) const
return strRet;
}
-UniValue help(const UniValue& params, bool fHelp)
+UniValue help(const JSONRPCRequest& jsonRequest)
{
- if (fHelp || params.size() > 1)
+ if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
throw runtime_error(
"help ( \"command\" )\n"
"\nList all commands, or get help for a specified command.\n"
@@ -241,17 +242,17 @@ UniValue help(const UniValue& params, bool fHelp)
);
string strCommand;
- if (params.size() > 0)
- strCommand = params[0].get_str();
+ if (jsonRequest.params.size() > 0)
+ strCommand = jsonRequest.params[0].get_str();
return tableRPC.help(strCommand);
}
-UniValue stop(const UniValue& params, bool fHelp)
+UniValue stop(const JSONRPCRequest& jsonRequest)
{
// Accept the deprecated and ignored 'detach' boolean argument
- if (fHelp || params.size() > 1)
+ if (jsonRequest.fHelp || jsonRequest.params.size() > 1)
throw runtime_error(
"stop\n"
"\nStop Bitcoin server.");
@@ -354,7 +355,7 @@ bool RPCIsInWarmup(std::string *outStatus)
return fRPCInWarmup;
}
-void JSONRequest::parse(const UniValue& valRequest)
+void JSONRPCRequest::parse(const UniValue& valRequest)
{
// Parse request
if (!valRequest.isObject())
@@ -388,11 +389,11 @@ static UniValue JSONRPCExecOne(const UniValue& req)
{
UniValue rpc_result(UniValue::VOBJ);
- JSONRequest jreq;
+ JSONRPCRequest jreq;
try {
jreq.parse(req);
- UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);
+ UniValue result = tableRPC.execute(jreq);
rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id);
}
catch (const UniValue& objError)
@@ -417,7 +418,7 @@ std::string JSONRPCExecBatch(const UniValue& vReq)
return ret.write() + "\n";
}
-UniValue CRPCTable::execute(const std::string &strMethod, const UniValue &params) const
+UniValue CRPCTable::execute(const JSONRPCRequest &request) const
{
// Return immediately if in warmup
{
@@ -427,7 +428,7 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue &params
}
// Find method
- const CRPCCommand *pcmd = tableRPC[strMethod];
+ const CRPCCommand *pcmd = tableRPC[request.strMethod];
if (!pcmd)
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
@@ -436,7 +437,7 @@ UniValue CRPCTable::execute(const std::string &strMethod, const UniValue &params
try
{
// Execute
- return pcmd->actor(params, false);
+ return pcmd->actor(request);
}
catch (const std::exception& e)
{
diff --git a/src/rpc/server.h b/src/rpc/server.h
index 4e0aa2c6d6..c59886222c 100644
--- a/src/rpc/server.h
+++ b/src/rpc/server.h
@@ -41,14 +41,17 @@ struct UniValueType {
UniValue::VType type;
};
-class JSONRequest
+class JSONRPCRequest
{
public:
UniValue id;
std::string strMethod;
UniValue params;
+ bool fHelp;
+ std::string URI;
+ std::string authUser;
- JSONRequest() { id = NullUniValue; }
+ JSONRPCRequest() { id = NullUniValue; params = NullUniValue; fHelp = false; }
void parse(const UniValue& valRequest);
};
@@ -122,7 +125,7 @@ void RPCUnsetTimerInterface(RPCTimerInterface *iface);
*/
void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds);
-typedef UniValue(*rpcfn_type)(const UniValue& params, bool fHelp);
+typedef UniValue(*rpcfn_type)(const JSONRPCRequest& jsonRequest);
class CRPCCommand
{
@@ -147,12 +150,11 @@ public:
/**
* Execute a method.
- * @param method Method to execute
- * @param params UniValue Array of arguments (JSON objects)
+ * @param request The JSONRPCRequest to execute
* @returns Result of the call.
* @throws an exception (UniValue) when an error happens.
*/
- UniValue execute(const std::string &method, const UniValue &params) const;
+ UniValue execute(const JSONRPCRequest &request) const;
/**
* Returns a list of registered commands
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 41756ea711..0e17ddc130 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -79,8 +79,20 @@ bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
return false;
}
} else {
- // Non-canonical public key: neither compressed nor uncompressed
- return false;
+ // Non-canonical public key: neither compressed nor uncompressed
+ return false;
+ }
+ return true;
+}
+
+bool static IsCompressedPubKey(const valtype &vchPubKey) {
+ if (vchPubKey.size() != 33) {
+ // Non-canonical public key: invalid length for compressed key
+ return false;
+ }
+ if (vchPubKey[0] != 0x02 && vchPubKey[0] != 0x03) {
+ // Non-canonical public key: invalid prefix for compressed key
+ return false;
}
return true;
}
@@ -199,10 +211,14 @@ bool CheckSignatureEncoding(const vector<unsigned char> &vchSig, unsigned int fl
return true;
}
-bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) {
- if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchSig)) {
+bool static CheckPubKeyEncoding(const valtype &vchPubKey, unsigned int flags, const SigVersion &sigversion, ScriptError* serror) {
+ if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchPubKey)) {
return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
}
+ // Only compressed keys are accepted in segwit
+ if ((flags & SCRIPT_VERIFY_WITNESS_PUBKEYTYPE) != 0 && sigversion == SIGVERSION_WITNESS_V0 && !IsCompressedPubKey(vchPubKey)) {
+ return set_error(serror, SCRIPT_ERR_WITNESS_PUBKEYTYPE);
+ }
return true;
}
@@ -874,12 +890,12 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// Subset of script starting at the most recent codeseparator
CScript scriptCode(pbegincodehash, pend);
- // Drop the signature, since there's no way for a signature to sign itself
+ // Drop the signature in pre-segwit scripts but not segwit scripts
if (sigversion == SIGVERSION_BASE) {
scriptCode.FindAndDelete(CScript(vchSig));
}
- if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) {
+ if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) {
//serror is set
return false;
}
@@ -935,7 +951,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// Subset of script starting at the most recent codeseparator
CScript scriptCode(pbegincodehash, pend);
- // Drop the signatures, since there's no way for a signature to sign itself
+ // Drop the signature in pre-segwit scripts but not segwit scripts
for (int k = 0; k < nSigsCount; k++)
{
valtype& vchSig = stacktop(-isig-k);
@@ -953,7 +969,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// Note how this makes the exact order of pubkey/signature evaluation
// distinguishable by CHECKMULTISIG NOT if the STRICTENC flag is set.
// See the script_(in)valid tests for details.
- if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, serror)) {
+ if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) {
// serror is set
return false;
}
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index 0adc9482ff..79894c5300 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -102,6 +102,10 @@ enum
// Signature(s) must be empty vector if an CHECK(MULTI)SIG operation failed
//
SCRIPT_VERIFY_NULLFAIL = (1U << 14),
+
+ // Public keys in segregated witness scripts must be compressed
+ //
+ SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1U << 15),
};
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);
diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp
index 0bf180341e..7467d23b2d 100644
--- a/src/script/ismine.cpp
+++ b/src/script/ismine.cpp
@@ -29,13 +29,25 @@ unsigned int HaveKeys(const vector<valtype>& pubkeys, const CKeyStore& keystore)
return nResult;
}
-isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest)
+isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, SigVersion sigversion)
+{
+ bool isInvalid = false;
+ return IsMine(keystore, scriptPubKey, isInvalid, sigversion);
+}
+
+isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, SigVersion sigversion)
+{
+ bool isInvalid = false;
+ return IsMine(keystore, dest, isInvalid, sigversion);
+}
+
+isminetype IsMine(const CKeyStore &keystore, const CTxDestination& dest, bool& isInvalid, SigVersion sigversion)
{
CScript script = GetScriptForDestination(dest);
- return IsMine(keystore, script);
+ return IsMine(keystore, script, isInvalid, sigversion);
}
-isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
+isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion sigversion)
{
vector<valtype> vSolutions;
txnouttype whichType;
@@ -53,12 +65,35 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
break;
case TX_PUBKEY:
keyID = CPubKey(vSolutions[0]).GetID();
+ if (sigversion != SIGVERSION_BASE && vSolutions[0].size() != 33) {
+ isInvalid = true;
+ return ISMINE_NO;
+ }
if (keystore.HaveKey(keyID))
return ISMINE_SPENDABLE;
break;
- case TX_PUBKEYHASH:
case TX_WITNESS_V0_KEYHASH:
+ {
+ if (!keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
+ // We do not support bare witness outputs unless the P2SH version of it would be
+ // acceptable as well. This protects against matching before segwit activates.
+ // This also applies to the P2WSH case.
+ break;
+ }
+ isminetype ret = ::IsMine(keystore, GetScriptForDestination(CKeyID(uint160(vSolutions[0]))), isInvalid, SIGVERSION_WITNESS_V0);
+ if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid))
+ return ret;
+ break;
+ }
+ case TX_PUBKEYHASH:
keyID = CKeyID(uint160(vSolutions[0]));
+ if (sigversion != SIGVERSION_BASE) {
+ CPubKey pubkey;
+ if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) {
+ isInvalid = true;
+ return ISMINE_NO;
+ }
+ }
if (keystore.HaveKey(keyID))
return ISMINE_SPENDABLE;
break;
@@ -67,21 +102,24 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
CScript subscript;
if (keystore.GetCScript(scriptID, subscript)) {
- isminetype ret = IsMine(keystore, subscript);
- if (ret == ISMINE_SPENDABLE)
+ isminetype ret = IsMine(keystore, subscript, isInvalid);
+ if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid))
return ret;
}
break;
}
case TX_WITNESS_V0_SCRIPTHASH:
{
+ if (!keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
+ break;
+ }
uint160 hash;
CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(hash.begin());
CScriptID scriptID = CScriptID(hash);
CScript subscript;
if (keystore.GetCScript(scriptID, subscript)) {
- isminetype ret = IsMine(keystore, subscript);
- if (ret == ISMINE_SPENDABLE)
+ isminetype ret = IsMine(keystore, subscript, isInvalid, SIGVERSION_WITNESS_V0);
+ if (ret == ISMINE_SPENDABLE || ret == ISMINE_WATCH_SOLVABLE || (ret == ISMINE_NO && isInvalid))
return ret;
}
break;
@@ -95,6 +133,14 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
// them) enable spend-out-from-under-you attacks, especially
// in shared-wallet situations.
vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
+ if (sigversion != SIGVERSION_BASE) {
+ for (size_t i = 0; i < keys.size(); i++) {
+ if (keys[i].size() != 33) {
+ isInvalid = true;
+ return ISMINE_NO;
+ }
+ }
+ }
if (HaveKeys(keys, keystore) == keys.size())
return ISMINE_SPENDABLE;
break;
diff --git a/src/script/ismine.h b/src/script/ismine.h
index 4b7db8802b..ec7a620e33 100644
--- a/src/script/ismine.h
+++ b/src/script/ismine.h
@@ -28,7 +28,14 @@ enum isminetype
/** used for bitflags of isminetype */
typedef uint8_t isminefilter;
-isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey);
-isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest);
+/* isInvalid becomes true when the script is found invalid by consensus or policy. This will terminate the recursion
+ * and return a ISMINE_NO immediately, as an invalid script should never be considered as "mine". This is needed as
+ * different SIGVERSION may have different network rules. Currently the only use of isInvalid is indicate uncompressed
+ * keys in SIGVERSION_WITNESS_V0 script, but could also be used in similar cases in the future
+ */
+isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, bool& isInvalid, SigVersion = SIGVERSION_BASE);
+isminetype IsMine(const CKeyStore& keystore, const CScript& scriptPubKey, SigVersion = SIGVERSION_BASE);
+isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, bool& isInvalid, SigVersion = SIGVERSION_BASE);
+isminetype IsMine(const CKeyStore& keystore, const CTxDestination& dest, SigVersion = SIGVERSION_BASE);
#endif // BITCOIN_SCRIPT_ISMINE_H
diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp
index e27b715c2c..2c5359fe8a 100644
--- a/src/script/script_error.cpp
+++ b/src/script/script_error.cpp
@@ -85,6 +85,8 @@ const char* ScriptErrorString(const ScriptError serror)
return "Witness requires only-redeemscript scriptSig";
case SCRIPT_ERR_WITNESS_UNEXPECTED:
return "Witness provided for non-witness script";
+ case SCRIPT_ERR_WITNESS_PUBKEYTYPE:
+ return "Using non-compressed keys in segwit";
case SCRIPT_ERR_UNKNOWN_ERROR:
case SCRIPT_ERR_ERROR_COUNT:
default: break;
diff --git a/src/script/script_error.h b/src/script/script_error.h
index bccfdb99e2..430836991b 100644
--- a/src/script/script_error.h
+++ b/src/script/script_error.h
@@ -62,6 +62,7 @@ typedef enum ScriptError_t
SCRIPT_ERR_WITNESS_MALLEATED,
SCRIPT_ERR_WITNESS_MALLEATED_P2SH,
SCRIPT_ERR_WITNESS_UNEXPECTED,
+ SCRIPT_ERR_WITNESS_PUBKEYTYPE,
SCRIPT_ERR_ERROR_COUNT
} ScriptError;
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 87f38d9c72..f552ad5bba 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -26,6 +26,10 @@ bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig,
if (!keystore->GetKey(address, key))
return false;
+ // Signing with uncompressed keys is disabled in witness scripts
+ if (sigversion == SIGVERSION_WITNESS_V0 && !key.IsCompressed())
+ return false;
+
uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion);
if (!key.Sign(hash, vchSig))
return false;
diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp
index 5ccaeb57bb..adff09f754 100644
--- a/src/test/addrman_tests.cpp
+++ b/src/test/addrman_tests.cpp
@@ -26,7 +26,7 @@ public:
void MakeDeterministic()
{
nKey.SetNull();
- seed_insecure_rand(true);
+ insecure_rand = FastRandomContext(true);
}
int RandomInt(int nMax)
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index e692326559..b487686136 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "coins.h"
-#include "random.h"
+#include "test_random.h"
#include "script/standard.h"
#include "uint256.h"
#include "utilstrencodings.h"
diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp
index ff0adae1d2..c7b4fb240c 100644
--- a/src/test/crypto_tests.cpp
+++ b/src/test/crypto_tests.cpp
@@ -9,7 +9,7 @@
#include "crypto/sha512.h"
#include "crypto/hmac_sha256.h"
#include "crypto/hmac_sha512.h"
-#include "random.h"
+#include "test_random.h"
#include "utilstrencodings.h"
#include "test/test_bitcoin.h"
diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json
index 06103ea5bd..5c054ed3e8 100644
--- a/src/test/data/script_tests.json
+++ b/src/test/data/script_tests.json
@@ -1855,6 +1855,8 @@
"OK",
"P2SH with CLEANSTACK"
],
+
+["Testing with uncompressed keys in witness v0 without WITNESS_PUBKEYTYPE"],
[
[
"304402200d461c140cfdfcf36b94961db57ae8c18d1cb80e9d95a9e47ac22470c1bf125502201c8dc1cbfef6a3ef90acbbb992ca22fe9466ee6f9d4898eda277a7ac3ab4b25101",
@@ -2139,7 +2141,371 @@
"P2PK with witness"
],
-["CHECKSEQUENCEVERIFY tests"],
+["Testing with compressed keys in witness v0 with WITNESS_PUBKEYTYPE"],
+[
+ [
+ "304402204256146fcf8e73b0fd817ffa2a4e408ff0418ff987dd08a4f485b62546f6c43c02203f3c8c3e2febc051e1222867f5f9d0eaf039d6792911c10940aa3cc74123378e01",
+ "210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x1863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "Basic P2WSH with compressed key"
+],
+[
+ [
+ "304402204edf27486f11432466b744df533e1acac727e0c83e5f912eb289a3df5bf8035f022075809fdd876ede40ad21667eba8b7e96394938f9c9c50f11b6a1280cce2cea8601",
+ "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
+ 0.00000001
+ ],
+ "",
+ "0 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "Basic P2WPKH with compressed key"
+],
+[
+ [
+ "304402203a549090cc46bce1e5e95c4922ea2c12747988e0207b04c42f81cdbe87bb1539022050f57a245b875fd5119c419aaf050bcdf41384f0765f04b809e5bced1fe7093d01",
+ "210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac",
+ 0.00000001
+ ],
+ "0x22 0x00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262",
+ "HASH160 0x14 0xe4300531190587e3880d4c3004f5355d88ff928d EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "Basic P2SH(P2WSH) with compressed key"
+],
+[
+ [
+ "304402201bc0d53046827f4a35a3166e33e3b3366c4085540dc383b95d21ed2ab11e368a0220333e78c6231214f5f8e59621e15d7eeab0d4e4d0796437e00bfbd2680c5f9c1701",
+ "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
+ 0.00000001
+ ],
+ "0x16 0x0014751e76e8199196d454941c45d1b3a323f1433bd6",
+ "HASH160 0x14 0xbcfeb728b584253d5f3f70bcb780e9ef218a68f4 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "Basic P2SH(P2WPKH) with compressed key"
+],
+
+["Testing with uncompressed keys in witness v0 with WITNESS_PUBKEYTYPE"],
+[
+ [
+ "304402200d461c140cfdfcf36b94961db57ae8c18d1cb80e9d95a9e47ac22470c1bf125502201c8dc1cbfef6a3ef90acbbb992ca22fe9466ee6f9d4898eda277a7ac3ab4b25101",
+ "410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0xb95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "Basic P2WSH"
+],
+[
+ [
+ "304402201e7216e5ccb3b61d46946ec6cc7e8c4e0117d13ac2fd4b152197e4805191c74202203e9903e33e84d9ee1dd13fb057afb7ccfb47006c23f6a067185efbc9dd780fc501",
+ "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
+ 0.00000001
+ ],
+ "",
+ "0 0x14 0x91b24bf9f5288532960ac687abb035127b1d28a5",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "Basic P2WPKH"
+],
+[
+ [
+ "3044022066e02c19a513049d49349cf5311a1b012b7c4fae023795a18ab1d91c23496c22022025e216342c8e07ce8ef51e8daee88f84306a9de66236cab230bb63067ded1ad301",
+ "410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac",
+ 0.00000001
+ ],
+ "0x22 0x0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64",
+ "HASH160 0x14 0xf386c2ba255cc56d20cfa6ea8b062f8b59945518 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "Basic P2SH(P2WSH)"
+],
+[
+ [
+ "304402200929d11561cd958460371200f82e9cae64c727a495715a31828e27a7ad57b36d0220361732ced04a6f97351ecca21a56d0b8cd4932c1da1f8f569a2b68e5e48aed7801",
+ "0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8",
+ 0.00000001
+ ],
+ "0x16 0x001491b24bf9f5288532960ac687abb035127b1d28a5",
+ "HASH160 0x14 0x17743beb429c55c942d2ec703b98c4d57c2df5c6 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "Basic P2SH(P2WPKH)"
+],
+
+["Testing P2WSH multisig with compressed keys"],
+[
+ [
+ "",
+ "304402207eb8a59b5c65fc3f6aeef77066556ed5c541948a53a3ba7f7c375b8eed76ee7502201e036a7a9a98ff919ff94dc905d67a1ec006f79ef7cff0708485c8bb79dce38e01",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x06c24420938f0fa3c1cb2707d867154220dca365cdbfa0dd2a83854730221460",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "P2WSH CHECKMULTISIG with compressed keys"
+],
+[
+ [
+ "",
+ "3044022033706aed33b8155d5486df3b9bca8cdd3bd4bdb5436dce46d72cdaba51d22b4002203626e94fe53a178af46624f17315c6931f20a30b103f5e044e1eda0c3fe185c601",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "0x22 0x002006c24420938f0fa3c1cb2707d867154220dca365cdbfa0dd2a83854730221460",
+ "HASH160 0x14 0x26282aad7c29369d15fed062a778b6100d31a340 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "P2SH(P2WSH) CHECKMULTISIG with compressed keys"
+],
+[
+ [
+ "",
+ "304402204048b7371ab1c544362efb89af0c80154747d665aa4fcfb2edfd2d161e57b42e02207e043748e96637080ffc3acbd4dcc6fee1e58d30f6d1269535f32188e5ddae7301",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x06c24420938f0fa3c1cb2707d867154220dca365cdbfa0dd2a83854730221460",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "P2WSH CHECKMULTISIG with compressed keys"
+],
+[
+ [
+ "",
+ "3044022073902ef0b8a554c36c44cc03c1b64df96ce2914ebcf946f5bb36078fd5245cdf02205b148f1ba127065fb8c83a5a9576f2dcd111739788ed4bb3ee08b2bd3860c91c01",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "0x22 0x002006c24420938f0fa3c1cb2707d867154220dca365cdbfa0dd2a83854730221460",
+ "HASH160 0x14 0x26282aad7c29369d15fed062a778b6100d31a340 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "P2SH(P2WSH) CHECKMULTISIG with compressed keys"
+],
+
+["Testing P2WSH multisig with compressed and uncompressed keys (first key being the key closer to the top of stack)"],
+[
+ [
+ "",
+ "304402202d092ededd1f060609dbf8cb76950634ff42b3e62cf4adb69ab92397b07d742302204ff886f8d0817491a96d1daccdcc820f6feb122ee6230143303100db37dfa79f01",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x08a6665ebfd43b02323423e764e185d98d1587f903b81507dbb69bfc41005efa",
+ "P2SH,WITNESS",
+ "OK",
+ "P2WSH CHECKMULTISIG with first key uncompressed and signing with the first key"
+],
+[
+ [
+ "",
+ "304402202dd7e91243f2235481ffb626c3b7baf2c859ae3a5a77fb750ef97b99a8125dc002204960de3d3c3ab9496e218ec57e5240e0e10a6f9546316fe240c216d45116d29301",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b852ae",
+ 0.00000001
+ ],
+ "0x22 0x002008a6665ebfd43b02323423e764e185d98d1587f903b81507dbb69bfc41005efa",
+ "HASH160 0x14 0x6f5ecd4b83b77f3c438f5214eff96454934fc5d1 EQUAL",
+ "P2SH,WITNESS",
+ "OK",
+ "P2SH(P2WSH) CHECKMULTISIG first key uncompressed and signing with the first key"
+],
+[
+ [
+ "",
+ "304402202d092ededd1f060609dbf8cb76950634ff42b3e62cf4adb69ab92397b07d742302204ff886f8d0817491a96d1daccdcc820f6feb122ee6230143303100db37dfa79f01",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x08a6665ebfd43b02323423e764e185d98d1587f903b81507dbb69bfc41005efa",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "P2WSH CHECKMULTISIG with first key uncompressed and signing with the first key"
+],
+[
+ [
+ "",
+ "304402202dd7e91243f2235481ffb626c3b7baf2c859ae3a5a77fb750ef97b99a8125dc002204960de3d3c3ab9496e218ec57e5240e0e10a6f9546316fe240c216d45116d29301",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b852ae",
+ 0.00000001
+ ],
+ "0x22 0x002008a6665ebfd43b02323423e764e185d98d1587f903b81507dbb69bfc41005efa",
+ "HASH160 0x14 0x6f5ecd4b83b77f3c438f5214eff96454934fc5d1 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the first key"
+],
+[
+ [
+ "",
+ "304402201e9e6f7deef5b2f21d8223c5189b7d5e82d237c10e97165dd08f547c4e5ce6ed02206796372eb1cc6acb52e13ee2d7f45807780bf96b132cb6697f69434be74b1af901",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x08a6665ebfd43b02323423e764e185d98d1587f903b81507dbb69bfc41005efa",
+ "P2SH,WITNESS",
+ "OK",
+ "P2WSH CHECKMULTISIG with first key uncompressed and signing with the second key"
+],
+[
+ [
+ "",
+ "3044022045e667f3f0f3147b95597a24babe9afecea1f649fd23637dfa7ed7e9f3ac18440220295748e81005231135289fe3a88338dabba55afa1bdb4478691337009d82b68d01",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b852ae",
+ 0.00000001
+ ],
+ "0x22 0x002008a6665ebfd43b02323423e764e185d98d1587f903b81507dbb69bfc41005efa",
+ "HASH160 0x14 0x6f5ecd4b83b77f3c438f5214eff96454934fc5d1 EQUAL",
+ "P2SH,WITNESS",
+ "OK",
+ "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the second key"
+],
+[
+ [
+ "",
+ "304402201e9e6f7deef5b2f21d8223c5189b7d5e82d237c10e97165dd08f547c4e5ce6ed02206796372eb1cc6acb52e13ee2d7f45807780bf96b132cb6697f69434be74b1af901",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x08a6665ebfd43b02323423e764e185d98d1587f903b81507dbb69bfc41005efa",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "P2WSH CHECKMULTISIG with first key uncompressed and signing with the second key"
+],
+[
+ [
+ "",
+ "3044022045e667f3f0f3147b95597a24babe9afecea1f649fd23637dfa7ed7e9f3ac18440220295748e81005231135289fe3a88338dabba55afa1bdb4478691337009d82b68d01",
+ "5121038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b852ae",
+ 0.00000001
+ ],
+ "0x22 0x002008a6665ebfd43b02323423e764e185d98d1587f903b81507dbb69bfc41005efa",
+ "HASH160 0x14 0x6f5ecd4b83b77f3c438f5214eff96454934fc5d1 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the second key"
+],
+[
+ [
+ "",
+ "3044022046f5367a261fd8f8d7de6eb390491344f8ec2501638fb9a1095a0599a21d3f4c02205c1b3b51d20091c5f1020841bbca87b44ebe25405c64e4acf758f2eae8665f8401",
+ "5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb",
+ "P2SH,WITNESS",
+ "OK",
+ "P2WSH CHECKMULTISIG with second key uncompressed and signing with the first key"
+],
+[
+ [
+ "",
+ "3044022053e210e4fb1881e6092fd75c3efc5163105599e246ded661c0ee2b5682cc2d6c02203a26b7ada8682a095b84c6d1b881637000b47d761fc837c4cee33555296d63f101",
+ "5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "0x22 0x0020230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb",
+ "HASH160 0x14 0x3478e7019ce61a68148f87549579b704cbe4c393 EQUAL",
+ "P2SH,WITNESS",
+ "OK",
+ "P2SH(P2WSH) CHECKMULTISIG second key uncompressed and signing with the first key"
+],
+[
+ [
+ "",
+ "3044022046f5367a261fd8f8d7de6eb390491344f8ec2501638fb9a1095a0599a21d3f4c02205c1b3b51d20091c5f1020841bbca87b44ebe25405c64e4acf758f2eae8665f8401",
+ "5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "P2WSH CHECKMULTISIG with second key uncompressed and signing with the first key should pass as the uncompressed key is not used"
+],
+[
+ [
+ "",
+ "3044022053e210e4fb1881e6092fd75c3efc5163105599e246ded661c0ee2b5682cc2d6c02203a26b7ada8682a095b84c6d1b881637000b47d761fc837c4cee33555296d63f101",
+ "5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "0x22 0x0020230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb",
+ "HASH160 0x14 0x3478e7019ce61a68148f87549579b704cbe4c393 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "OK",
+ "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the first key should pass as the uncompressed key is not used"
+],
+[
+ [
+ "",
+ "304402206c6d9f5daf85b54af2a93ec38b15ab27f205dbf5c735365ff12451e43613d1f40220736a44be63423ed5ebf53491618b7cc3d8a5093861908da853739c73717938b701",
+ "5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb",
+ "P2SH,WITNESS",
+ "OK",
+ "P2WSH CHECKMULTISIG with second key uncompressed and signing with the second key"
+],
+[
+ [
+ "",
+ "30440220687871bc6144012d75baf585bb26ce13997f7d8c626f4d8825b069c3b2d064470220108936fe1c57327764782253e99090b09c203ec400ed35ce9e026ce2ecf842a001",
+ "5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "0x22 0x0020230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb",
+ "HASH160 0x14 0x3478e7019ce61a68148f87549579b704cbe4c393 EQUAL",
+ "P2SH,WITNESS",
+ "OK",
+ "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the second key"
+],
+[
+ [
+ "",
+ "304402206c6d9f5daf85b54af2a93ec38b15ab27f205dbf5c735365ff12451e43613d1f40220736a44be63423ed5ebf53491618b7cc3d8a5093861908da853739c73717938b701",
+ "5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "",
+ "0 0x20 0x230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "P2WSH CHECKMULTISIG with second key uncompressed and signing with the second key"
+],
+[
+ [
+ "",
+ "30440220687871bc6144012d75baf585bb26ce13997f7d8c626f4d8825b069c3b2d064470220108936fe1c57327764782253e99090b09c203ec400ed35ce9e026ce2ecf842a001",
+ "5141048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179852ae",
+ 0.00000001
+ ],
+ "0x22 0x0020230828ed48871f0f362ce9432aa52f620f442cc8d9ce7a8b5e798365595a38bb",
+ "HASH160 0x14 0x3478e7019ce61a68148f87549579b704cbe4c393 EQUAL",
+ "P2SH,WITNESS,WITNESS_PUBKEYTYPE",
+ "WITNESS_PUBKEYTYPE",
+ "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the second key"
+],
+
+["CHECKSEQUENCEVERIFY tests"],
["", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "INVALID_STACK_OPERATION", "CSV automatically fails on a empty stack"],
["-1", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY", "NEGATIVE_LOCKTIME", "CSV automatically fails if stack top is negative"],
["0x0100", "CHECKSEQUENCEVERIFY", "CHECKSEQUENCEVERIFY,MINIMALDATA", "UNKNOWN_ERROR", "CSV fails if stack top is not minimally encoded"],
diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json
index f8baee0577..f7d9e1847f 100644
--- a/src/test/data/tx_invalid.json
+++ b/src/test/data/tx_invalid.json
@@ -314,5 +314,31 @@
[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x60 0x21 0xff25429251b5a84f452230a3c75fd886b7fc5a7865ce4a7bb7a9d7c5be6da3dbff", 1000]],
"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff01e803000000000000015100000000", "P2SH,WITNESS,DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"],
+["FindAndDelete tests"],
+["This is a test of FindAndDelete. The first tx is a spend of normal scriptPubKey and the second tx is a spend of bare P2WSH."],
+["The redeemScript/witnessScript is CHECKSIGVERIFY <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01>."],
+["The signature is <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01> <pubkey>,"],
+["where the pubkey is obtained through key recovery with sig and the wrong sighash."],
+["This is to show that FindAndDelete is applied only to non-segwit scripts"],
+["To show that the tests are 'correctly wrong', they should pass by modifying OP_CHECKSIG under interpreter.cpp"],
+["by replacing (sigversion == SIGVERSION_BASE) with (sigversion != SIGVERSION_BASE)"],
+["Non-segwit: wrong sighash (without FindAndDelete) = 1ba1fe3bc90c5d1265460e684ce6774e324f0fabdf67619eda729e64e8b6bc08"],
+[[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7000, "HASH160 0x14 0x0c746489e2d83cdbb5b90b432773342ba809c134 EQUAL", 200000]],
+"010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f1581b0000b64830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012103b12a1ec8428fc74166926318c15e17408fea82dbb157575e16a8c365f546248f4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01ffffffff0101000000000000000000000000", "P2SH,WITNESS"],
+["BIP143: wrong sighash (with FindAndDelete) = 71c9cd9b2869b9c70b01b1f0360c148f42dee72297db312638df136f43311f23"],
+[[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7500, "0x00 0x20 0x9e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19", 200000]],
+"0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9d7ed6e161f0e255c10bbfcca0128a9e2035c2c8da58899c54d22d3a31afdef4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000", "P2SH,WITNESS"],
+["This is multisig version of the FindAndDelete tests"],
+["Script is 2 CHECKMULTISIGVERIFY <sig1> <sig2> DROP"],
+["52af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175"],
+["Signature is 0 <sig1> <sig2> 2 <key1> <key2>"],
+["Should pass by replacing (sigversion == SIGVERSION_BASE) with (sigversion != SIGVERSION_BASE) under OP_CHECKMULTISIG"],
+["Non-segwit: wrong sighash (without FindAndDelete) = 4bc6a53e8e16ef508c19e38bba08831daba85228b0211f323d4cb0999cf2a5e8"],
+[[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7000, "HASH160 0x14 0x5748407f5ca5cdca53ba30b79040260770c9ee1b EQUAL", 200000]],
+"01000000019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a662896581b0000fd6f01004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596015221023fd5dd42b44769c5653cbc5947ff30ab8871f240ad0c0e7432aefe84b5b4ff3421039d52178dbde360b83f19cf348deb04fa8360e1bf5634577be8e50fafc2b0e4ef4c9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175ffffffff0101000000000000000000000000", "P2SH,WITNESS"],
+["BIP143: wrong sighash (with FindAndDelete) = 17c50ec2181ecdfdc85ca081174b248199ba81fff730794d4f69b8ec031f2dce"],
+[[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7500, "0x00 0x20 0x9b66c15b4e0b4eb49fa877982cafded24859fe5b0e2dbfbe4f0df1de7743fd52", 200000]],
+"010000000001019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d000000ffffffff0101000000000000000007004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c03959601010221023cb6055f4b57a1580c5a753e19610cafaedf7e0ff377731c77837fd666eae1712102c1b1db303ac232ffa8e5e7cc2cf5f96c6e40d3e6914061204c0541cb2043a0969552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596017500000000", "P2SH,WITNESS"],
+
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
index 1ea70135b4..2f299aa5fe 100644
--- a/src/test/data/tx_valid.json
+++ b/src/test/data/tx_valid.json
@@ -487,5 +487,28 @@
[[["6eb98797a21c6c10aa74edf29d618be109f48a8e94c694f3701e08ca69186436", 1, "HASH160 0x14 0x9993a429037b5d912407a71c252019287b8d27a5 EQUAL", 987654321]],
"0100000000010136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000023220020a16b5755f7f6f96dbd65f5f0d6ab9418b89af4b1f14a1bb8a09062c35f0dcb54ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac080047304402206ac44d672dac41f9b00e28f4df20c52eeb087207e8d758d76d92c6fab3b73e2b0220367750dbbe19290069cba53d096f44530e4f98acaa594810388cf7409a1870ce01473044022068c7946a43232757cbdf9176f009a928e1cd9a1a8c212f15c1e11ac9f2925d9002205b75f937ff2f9f3c1246e547e54f62e027f64eefa2695578cc6432cdabce271502473044022059ebf56d98010a932cf8ecfec54c48e6139ed6adb0728c09cbe1e4fa0915302e022007cd986c8fa870ff5d2b3a89139c9fe7e499259875357e20fcbb15571c76795403483045022100fbefd94bd0a488d50b79102b5dad4ab6ced30c4069f1eaa69a4b5a763414067e02203156c6a5c9cf88f91265f5a942e96213afae16d83321c8b31bb342142a14d16381483045022100a5263ea0553ba89221984bd7f0b13613db16e7a70c549a86de0cc0444141a407022005c360ef0ae5a5d4f9f2f87a56c1546cc8268cab08c73501d6b3be2e1e1a8a08824730440220525406a1482936d5a21888260dc165497a90a15669636d8edca6b9fe490d309c022032af0c646a34a44d1f4576bf6a4a74b67940f8faa84c7df9abe12a01a11e2b4783cf56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b14862c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b56ae00000000", "P2SH,WITNESS"],
+["FindAndDelete tests"],
+["This is a test of FindAndDelete. The first tx is a spend of normal P2SH and the second tx is a spend of bare P2WSH."],
+["The redeemScript/witnessScript is CHECKSIGVERIFY <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01>."],
+["The signature is <0x30450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01> <pubkey>,"],
+["where the pubkey is obtained through key recovery with sig and correct sighash."],
+["This is to show that FindAndDelete is applied only to non-segwit scripts"],
+["Non-segwit: correct sighash (with FindAndDelete) = 1ba1fe3bc90c5d1265460e684ce6774e324f0fabdf67619eda729e64e8b6bc08"],
+[[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7000, "HASH160 0x14 0x0c746489e2d83cdbb5b90b432773342ba809c134 EQUAL", 200000]],
+"010000000169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f1581b0000b64830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0121037a3fb04bcdb09eba90f69961ba1692a3528e45e67c85b200df820212d7594d334aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e01ffffffff0101000000000000000000000000", "P2SH,WITNESS"],
+["BIP143: correct sighash (without FindAndDelete) = 71c9cd9b2869b9c70b01b1f0360c148f42dee72297db312638df136f43311f23"],
+[[["f18783ace138abac5d3a7a5cf08e88fe6912f267ef936452e0c27d090621c169", 7500, "0x00 0x20 0x9e1be07558ea5cc8e02ed1d80c0911048afad949affa36d5c3951e3159dbea19", 200000]],
+"0100000000010169c12106097dc2e0526493ef67f21269fe888ef05c7a3a5dacab38e1ac8387f14c1d000000ffffffff01010000000000000000034830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e012102a9781d66b61fb5a7ef00ac5ad5bc6ffc78be7b44a566e3c87870e1079368df4c4aad4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0100000000", "P2SH,WITNESS"],
+["This is multisig version of the FindAndDelete tests"],
+["Script is 2 CHECKMULTISIGVERIFY <sig1> <sig2> DROP"],
+["52af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175"],
+["Signature is 0 <sig1> <sig2> 2 <key1> <key2>"],
+["Non-segwit: correct sighash (with FindAndDelete) = 1d50f00ba4db2917b903b0ec5002e017343bb38876398c9510570f5dce099295"],
+[[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7000, "HASH160 0x14 0x5748407f5ca5cdca53ba30b79040260770c9ee1b EQUAL", 200000]],
+"01000000019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a662896581b0000fd6f01004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c03959601522102cd74a2809ffeeed0092bc124fd79836706e41f048db3f6ae9df8708cefb83a1c2102e615999372426e46fd107b76eaf007156a507584aa2cc21de9eee3bdbd26d36c4c9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960175ffffffff0101000000000000000000000000", "P2SH,WITNESS"],
+["BIP143: correct sighash (without FindAndDelete) = c1628a1e7c67f14ca0c27c06e4fdeec2e6d1a73c7a91d7c046ff83e835aebb72"],
+[[["9628667ad48219a169b41b020800162287d2c0f713c04157e95c484a8dcb7592", 7500, "0x00 0x20 0x9b66c15b4e0b4eb49fa877982cafded24859fe5b0e2dbfbe4f0df1de7743fd52", 200000]],
+"010000000001019275cb8d4a485ce95741c013f7c0d28722160008021bb469a11982d47a6628964c1d000000ffffffff0101000000000000000007004830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c0395960101022102966f109c54e85d3aee8321301136cedeb9fc710fdef58a9de8a73942f8e567c021034ffc99dd9a79dd3cb31e2ab3e0b09e0e67db41ac068c625cd1f491576016c84e9552af4830450220487fb382c4974de3f7d834c1b617fe15860828c7f96454490edd6d891556dcc9022100baf95feb48f845d5bfc9882eb6aeefa1bc3790e39f59eaa46ff7f15ae626c53e0148304502205286f726690b2e9b0207f0345711e63fa7012045b9eb0f19c2458ce1db90cf43022100e89f17f86abc5b149eba4115d4f128bcf45d77fb3ecdd34f594091340c039596017500000000", "P2SH,WITNESS"],
+
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp
index b40ab848dc..66ca381ea7 100644
--- a/src/test/merkle_tests.cpp
+++ b/src/test/merkle_tests.cpp
@@ -4,7 +4,7 @@
#include "consensus/merkle.h"
#include "test/test_bitcoin.h"
-#include "random.h"
+#include "test_random.h"
#include <boost/test/unit_test.hpp>
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index d3aa2364d1..d6d7b5716e 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -18,6 +18,8 @@
#include "test/test_bitcoin.h"
+#include <memory>
+
#include <boost/test/unit_test.hpp>
BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup)
@@ -105,7 +107,7 @@ void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey,
uint256 hashHighFeeTx = tx.GetHash();
mempool.addUnchecked(hashHighFeeTx, entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx));
- CBlockTemplate *pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
+ std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
BOOST_CHECK(pblocktemplate->block.vtx[1].GetHash() == hashParentTx);
BOOST_CHECK(pblocktemplate->block.vtx[2].GetHash() == hashHighFeeTx);
BOOST_CHECK(pblocktemplate->block.vtx[3].GetHash() == hashMediumFeeTx);
@@ -184,7 +186,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
// Note that by default, these tests run with size accounting enabled.
const CChainParams& chainparams = Params(CBaseChainParams::MAIN);
CScript scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
- CBlockTemplate *pblocktemplate;
+ std::unique_ptr<CBlockTemplate> pblocktemplate;
CMutableTransaction tx,tx2;
CScript script;
uint256 hash;
@@ -222,15 +224,13 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
pblock->nNonce = blockinfo[i].nonce;
CValidationState state;
- BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL, connman));
+ BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL));
BOOST_CHECK(state.IsValid());
pblock->hashPrevBlock = pblock->GetHash();
}
- delete pblocktemplate;
// Just to make sure we can still make simple blocks
BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
- delete pblocktemplate;
const CAmount BLOCKSUBSIDY = 50*COIN;
const CAmount LOWFEE = CENT;
@@ -269,7 +269,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[0].prevout.hash = hash;
}
BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
- delete pblocktemplate;
mempool.clear();
// block size > limit
@@ -290,7 +289,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.vin[0].prevout.hash = hash;
}
BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
- delete pblocktemplate;
mempool.clear();
// orphan in mempool, template creation fails
@@ -314,7 +312,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
hash = tx.GetHash();
mempool.addUnchecked(hash, entry.Fee(HIGHERFEE).Time(GetTime()).SpendsCoinbase(true).FromTx(tx));
BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
- delete pblocktemplate;
mempool.clear();
// coinbase in mempool, template creation fails
@@ -372,7 +369,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
chainActive.SetTip(next);
}
BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
- delete pblocktemplate;
// Extend to a 210000-long block chain.
while (chainActive.Tip()->nHeight < 210000) {
CBlockIndex* prev = chainActive.Tip();
@@ -385,7 +381,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
chainActive.SetTip(next);
}
BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
- delete pblocktemplate;
// Delete the dummy blocks again.
while (chainActive.Tip()->nHeight > nHeight) {
CBlockIndex* del = chainActive.Tip();
@@ -478,7 +473,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
// but relative locked txs will if inconsistently added to mempool.
// For now these will still generate a valid template until BIP68 soft fork
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3);
- delete pblocktemplate;
// However if we advance height by 1 and time by 512, all of them should be mined
for (int i = 0; i < CBlockIndex::nMedianTimeSpan; i++)
chainActive.Tip()->GetAncestor(chainActive.Tip()->nHeight - i)->nTime += 512; //Trick the MedianTimePast
@@ -487,7 +481,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
BOOST_CHECK(pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey));
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 5);
- delete pblocktemplate;
chainActive.Tip()->nHeight--;
SetMockTime(0);
diff --git a/src/test/net_tests.cpp b/src/test/net_tests.cpp
index 4a7d6e778f..f4b5768693 100644
--- a/src/test/net_tests.cpp
+++ b/src/test/net_tests.cpp
@@ -23,7 +23,7 @@ public:
void MakeDeterministic()
{
nKey.SetNull();
- seed_insecure_rand(true);
+ insecure_rand = FastRandomContext(true);
}
};
diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp
index e9c8691745..b7f83d38f0 100644
--- a/src/test/pmt_tests.cpp
+++ b/src/test/pmt_tests.cpp
@@ -9,7 +9,7 @@
#include "uint256.h"
#include "arith_uint256.h"
#include "version.h"
-#include "random.h"
+#include "test_random.h"
#include "test/test_bitcoin.h"
#include <vector>
diff --git a/src/test/prevector_tests.cpp b/src/test/prevector_tests.cpp
index b8c45ca564..6cad02e738 100644
--- a/src/test/prevector_tests.cpp
+++ b/src/test/prevector_tests.cpp
@@ -4,7 +4,7 @@
#include <vector>
#include "prevector.h"
-#include "random.h"
+#include "test_random.h"
#include "serialize.h"
#include "streams.h"
@@ -27,8 +27,7 @@ class prevector_tester {
typedef typename pretype::size_type Size;
bool passed = true;
- uint32_t insecure_rand_Rz_cache;
- uint32_t insecure_rand_Rw_cache;
+ FastRandomContext rand_cache;
template <typename A, typename B>
@@ -171,15 +170,14 @@ public:
test();
}
~prevector_tester() {
- BOOST_CHECK_MESSAGE(passed, "insecure_rand_Rz: "
- << insecure_rand_Rz_cache
+ BOOST_CHECK_MESSAGE(passed, "insecure_rand_Rz: "
+ << rand_cache.Rz
<< ", insecure_rand_Rw: "
- << insecure_rand_Rw_cache);
+ << rand_cache.Rw);
}
prevector_tester() {
seed_insecure_rand();
- insecure_rand_Rz_cache = insecure_rand_Rz;
- insecure_rand_Rw_cache = insecure_rand_Rw;
+ rand_cache = insecure_rand_ctx;
}
};
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index a15915aad2..a3d1a25589 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -24,11 +24,14 @@ UniValue CallRPC(string args)
boost::split(vArgs, args, boost::is_any_of(" \t"));
string strMethod = vArgs[0];
vArgs.erase(vArgs.begin());
- UniValue params = RPCConvertValues(strMethod, vArgs);
+ JSONRPCRequest request;
+ request.strMethod = strMethod;
+ request.params = RPCConvertValues(strMethod, vArgs);
+ request.fHelp = false;
BOOST_CHECK(tableRPC[strMethod]);
rpcfn_type method = tableRPC[strMethod]->actor;
try {
- UniValue result = (*method)(params, false);
+ UniValue result = (*method)(request);
return result;
}
catch (const UniValue& objError) {
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index aa12dfbd54..891ecf5015 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -42,8 +42,6 @@ static void MicroSleep(uint64_t n)
BOOST_AUTO_TEST_CASE(manythreads)
{
- seed_insecure_rand(false);
-
// Stress test: hundreds of microsecond-scheduled tasks,
// serviced by 10 threads.
//
@@ -58,7 +56,7 @@ BOOST_AUTO_TEST_CASE(manythreads)
boost::mutex counterMutex[10];
int counter[10] = { 0 };
- boost::random::mt19937 rng(insecure_rand());
+ boost::random::mt19937 rng(42);
boost::random::uniform_int_distribution<> zeroToNine(0, 9);
boost::random::uniform_int_distribution<> randomMsec(-11, 1000);
boost::random::uniform_int_distribution<> randomDelta(-1000, 1000);
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index 7971b5122f..561adb8ea2 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -99,6 +99,7 @@ static ScriptErrorDesc script_errors[]={
{SCRIPT_ERR_WITNESS_MALLEATED, "WITNESS_MALLEATED"},
{SCRIPT_ERR_WITNESS_MALLEATED_P2SH, "WITNESS_MALLEATED_P2SH"},
{SCRIPT_ERR_WITNESS_UNEXPECTED, "WITNESS_UNEXPECTED"},
+ {SCRIPT_ERR_WITNESS_PUBKEYTYPE, "WITNESS_PUBKEYTYPE"},
};
const char *FormatScriptError(ScriptError_t err)
@@ -825,6 +826,99 @@ BOOST_AUTO_TEST_CASE(script_build)
"P2PK with witness", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH
).PushSig(keys.key0).Push("0").AsWit().ScriptError(SCRIPT_ERR_WITNESS_UNEXPECTED));
+ // Compressed keys should pass SCRIPT_VERIFY_WITNESS_PUBKEYTYPE
+ tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG,
+ "Basic P2WSH with compressed key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH,
+ 0, 1).PushWitSig(keys.key0C).PushWitRedeem());
+ tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C),
+ "Basic P2WPKH with compressed key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_PKH,
+ 0, 1).PushWitSig(keys.key0C).Push(keys.pubkey0C).AsWit());
+ tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C) << OP_CHECKSIG,
+ "Basic P2SH(P2WSH) with compressed key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH,
+ 0, 1).PushWitSig(keys.key0C).PushWitRedeem().PushRedeem());
+ tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0C),
+ "Basic P2SH(P2WPKH) with compressed key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_PKH,
+ 0, 1).PushWitSig(keys.key0C).Push(keys.pubkey0C).AsWit().PushRedeem());
+
+ // Testing uncompressed key in witness with SCRIPT_VERIFY_WITNESS_PUBKEYTYPE
+ tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
+ "Basic P2WSH", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH,
+ 0, 1).PushWitSig(keys.key0).PushWitRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+ tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0),
+ "Basic P2WPKH", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_PKH,
+ 0, 1).PushWitSig(keys.key0).Push(keys.pubkey0).AsWit().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+ tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0) << OP_CHECKSIG,
+ "Basic P2SH(P2WSH)", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH,
+ 0, 1).PushWitSig(keys.key0).PushWitRedeem().PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+ tests.push_back(TestBuilder(CScript() << ToByteVector(keys.pubkey0),
+ "Basic P2SH(P2WPKH)", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_PKH,
+ 0, 1).PushWitSig(keys.key0).Push(keys.pubkey0).AsWit().PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+
+ // P2WSH 1-of-2 multisig with compressed keys
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with compressed keys", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG with compressed keys", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem().PushRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with compressed keys", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG with compressed keys", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem().PushRedeem());
+
+ // P2WSH 1-of-2 multisig with first key uncompressed
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with first key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0).PushWitRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG first key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0).PushWitRedeem().PushRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with first key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0).PushWitRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0).PushWitRedeem().PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with first key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem().PushRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with first key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1C) << ToByteVector(keys.pubkey0) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG with first key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1C).PushWitRedeem().PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+ // P2WSH 1-of-2 multisig with second key uncompressed
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with second key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG second key uncompressed and signing with the first key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem().PushRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with second key uncompressed and signing with the first key should pass as the uncompressed key is not used", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the first key should pass as the uncompressed key is not used", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key0C).PushWitRedeem().PushRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with second key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1).PushWitRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1).PushWitRedeem().PushRedeem());
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2WSH CHECKMULTISIG with second key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, false, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1).PushWitRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+ tests.push_back(TestBuilder(CScript() << OP_1 << ToByteVector(keys.pubkey1) << ToByteVector(keys.pubkey0C) << OP_2 << OP_CHECKMULTISIG,
+ "P2SH(P2WSH) CHECKMULTISIG with second key uncompressed and signing with the second key", SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, true, WITNESS_SH,
+ 0, 1).Push(CScript()).AsWit().PushWitSig(keys.key1).PushWitRedeem().PushRedeem().ScriptError(SCRIPT_ERR_WITNESS_PUBKEYTYPE));
+
std::set<std::string> tests_set;
{
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index 4a48347b70..0b1050d020 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -6,7 +6,7 @@
#include "data/sighash.json.h"
#include "hash.h"
#include "main.h" // For CheckTransaction
-#include "random.h"
+#include "test_random.h"
#include "script/interpreter.h"
#include "script/script.h"
#include "serialize.h"
diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp
index f14b902fe1..b19f8fbffb 100644
--- a/src/test/skiplist_tests.cpp
+++ b/src/test/skiplist_tests.cpp
@@ -3,7 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "chain.h"
-#include "random.h"
+#include "test_random.h"
#include "util.h"
#include "test/test_bitcoin.h"
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 02843d8525..98f4ed939f 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -22,11 +22,14 @@
#include "test/testutil.h"
+#include <memory>
+
#include <boost/filesystem.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/thread.hpp>
std::unique_ptr<CConnman> g_connman;
+FastRandomContext insecure_rand_ctx(true);
extern bool fPrintToConsole;
extern void noui_connect();
@@ -110,7 +113,7 @@ CBlock
TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey)
{
const CChainParams& chainparams = Params();
- CBlockTemplate *pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
+ std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey);
CBlock& block = pblocktemplate->block;
// Replace mempool-selected txns with just coinbase plus passed-in txns:
@@ -124,10 +127,9 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>&
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
CValidationState state;
- ProcessNewBlock(state, chainparams, NULL, &block, true, NULL, connman);
+ ProcessNewBlock(state, chainparams, NULL, &block, true, NULL);
CBlock result = block;
- delete pblocktemplate;
return result;
}
diff --git a/src/test/test_random.h b/src/test/test_random.h
new file mode 100644
index 0000000000..e61b92b7bc
--- /dev/null
+++ b/src/test/test_random.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_TEST_RANDOM_H
+#define BITCOIN_TEST_RANDOM_H
+
+#include "random.h"
+
+extern FastRandomContext insecure_rand_ctx;
+
+static inline void seed_insecure_rand(bool fDeterministic = false)
+{
+ insecure_rand_ctx = FastRandomContext(fDeterministic);
+}
+
+static inline uint32_t insecure_rand(void)
+{
+ return insecure_rand_ctx.rand32();
+}
+
+#endif
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 6163d2f630..34d9547f3d 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2011-2015 The Bitcoin Core developers
+// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -55,7 +55,8 @@ static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of
(string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)
(string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)
(string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS)
- (string("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM);
+ (string("DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM)
+ (string("WITNESS_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_WITNESS_PUBKEYTYPE);
unsigned int ParseScriptFlags(string strFlags)
{
@@ -429,7 +430,7 @@ BOOST_AUTO_TEST_CASE(test_big_witness_transaction) {
mtx.nVersion = 1;
CKey key;
- key.MakeNewKey(false);
+ key.MakeNewKey(true); // Need to use compressed keys in segwit or the signing will fail
CBasicKeyStore keystore;
keystore.AddKeyPubKey(key, key.GetPubKey());
CKeyID hash = key.GetPubKey().GetID();
@@ -625,30 +626,13 @@ BOOST_AUTO_TEST_CASE(test_witness)
CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
- // Witness pay-to-uncompressed-pubkey (v1).
- CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey1L), output1, input1);
- CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey2L), output2, input2);
- CheckWithFlag(output1, input1, 0, true);
- CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
- CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true);
- CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
- CheckWithFlag(output1, input2, 0, true);
- CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, true);
- CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
- CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
+ // Signing disabled for witness pay-to-uncompressed-pubkey (v1).
+ CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey1L), output1, input1, false);
+ CreateCreditAndSpend(keystore, GetScriptForWitness(scriptPubkey2L), output2, input2, false);
- // P2SH witness pay-to-uncompressed-pubkey (v1).
- CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey1L))), output1, input1);
- CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey2L))), output2, input2);
- ReplaceRedeemScript(input2.vin[0].scriptSig, GetScriptForWitness(scriptPubkey1L));
- CheckWithFlag(output1, input1, 0, true);
- CheckWithFlag(output1, input1, SCRIPT_VERIFY_P2SH, true);
- CheckWithFlag(output1, input1, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, true);
- CheckWithFlag(output1, input1, STANDARD_SCRIPT_VERIFY_FLAGS, true);
- CheckWithFlag(output1, input2, 0, true);
- CheckWithFlag(output1, input2, SCRIPT_VERIFY_P2SH, true);
- CheckWithFlag(output1, input2, SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH, false);
- CheckWithFlag(output1, input2, STANDARD_SCRIPT_VERIFY_FLAGS, false);
+ // Signing disabled for P2SH witness pay-to-uncompressed-pubkey (v1).
+ CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey1L))), output1, input1, false);
+ CreateCreditAndSpend(keystore, GetScriptForDestination(CScriptID(GetScriptForWitness(scriptPubkey2L))), output2, input2, false);
// Normal 2-of-2 multisig
CreateCreditAndSpend(keystore, scriptMulti, output1, input1, false);
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index efd4498747..0f1c7ab222 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -6,7 +6,7 @@
#include "clientversion.h"
#include "primitives/transaction.h"
-#include "random.h"
+#include "test_random.h"
#include "sync.h"
#include "utilstrencodings.h"
#include "utilmoneystr.h"
diff --git a/src/test/versionbits_tests.cpp b/src/test/versionbits_tests.cpp
index 1f86a06a3f..784e796998 100644
--- a/src/test/versionbits_tests.cpp
+++ b/src/test/versionbits_tests.cpp
@@ -1,9 +1,9 @@
-// Copyright (c) 2014-2015 The Bitcoin Core developers
+// Copyright (c) 2014-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "chain.h"
-#include "random.h"
+#include "test_random.h"
#include "versionbits.h"
#include "test/test_bitcoin.h"
#include "chainparams.h"
@@ -30,6 +30,7 @@ public:
bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const { return (pindex->nVersion & 0x100); }
ThresholdState GetStateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, paramsDummy, cache); }
+ int GetStateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, paramsDummy, cache); }
};
#define CHECKERS 6
@@ -78,6 +79,16 @@ public:
return *this;
}
+ VersionBitsTester& TestStateSinceHeight(int height) {
+ for (int i = 0; i < CHECKERS; i++) {
+ if ((insecure_rand() & ((1 << i) - 1)) == 0) {
+ BOOST_CHECK_MESSAGE(checker[i].GetStateSinceHeightFor(vpblock.empty() ? NULL : vpblock.back()) == height, strprintf("Test %i for StateSinceHeight", num));
+ }
+ }
+ num++;
+ return *this;
+ }
+
VersionBitsTester& TestDefined() {
for (int i = 0; i < CHECKERS; i++) {
if ((insecure_rand() & ((1 << i) - 1)) == 0) {
@@ -137,53 +148,64 @@ BOOST_AUTO_TEST_CASE(versionbits_test)
{
for (int i = 0; i < 64; i++) {
// DEFINED -> FAILED
- VersionBitsTester().TestDefined()
- .Mine(1, TestTime(1), 0x100).TestDefined()
- .Mine(11, TestTime(11), 0x100).TestDefined()
- .Mine(989, TestTime(989), 0x100).TestDefined()
- .Mine(999, TestTime(20000), 0x100).TestDefined()
- .Mine(1000, TestTime(20000), 0x100).TestFailed()
- .Mine(1999, TestTime(30001), 0x100).TestFailed()
- .Mine(2000, TestTime(30002), 0x100).TestFailed()
- .Mine(2001, TestTime(30003), 0x100).TestFailed()
- .Mine(2999, TestTime(30004), 0x100).TestFailed()
- .Mine(3000, TestTime(30005), 0x100).TestFailed()
+ VersionBitsTester().TestDefined().TestStateSinceHeight(0)
+ .Mine(1, TestTime(1), 0x100).TestDefined().TestStateSinceHeight(0)
+ .Mine(11, TestTime(11), 0x100).TestDefined().TestStateSinceHeight(0)
+ .Mine(989, TestTime(989), 0x100).TestDefined().TestStateSinceHeight(0)
+ .Mine(999, TestTime(20000), 0x100).TestDefined().TestStateSinceHeight(0)
+ .Mine(1000, TestTime(20000), 0x100).TestFailed().TestStateSinceHeight(1000)
+ .Mine(1999, TestTime(30001), 0x100).TestFailed().TestStateSinceHeight(1000)
+ .Mine(2000, TestTime(30002), 0x100).TestFailed().TestStateSinceHeight(1000)
+ .Mine(2001, TestTime(30003), 0x100).TestFailed().TestStateSinceHeight(1000)
+ .Mine(2999, TestTime(30004), 0x100).TestFailed().TestStateSinceHeight(1000)
+ .Mine(3000, TestTime(30005), 0x100).TestFailed().TestStateSinceHeight(1000)
// DEFINED -> STARTED -> FAILED
- .Reset().TestDefined()
- .Mine(1, TestTime(1), 0).TestDefined()
- .Mine(1000, TestTime(10000) - 1, 0x100).TestDefined() // One second more and it would be defined
- .Mine(2000, TestTime(10000), 0x100).TestStarted() // So that's what happens the next period
- .Mine(2051, TestTime(10010), 0).TestStarted() // 51 old blocks
- .Mine(2950, TestTime(10020), 0x100).TestStarted() // 899 new blocks
- .Mine(3000, TestTime(20000), 0).TestFailed() // 50 old blocks (so 899 out of the past 1000)
- .Mine(4000, TestTime(20010), 0x100).TestFailed()
+ .Reset().TestDefined().TestStateSinceHeight(0)
+ .Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)
+ .Mine(1000, TestTime(10000) - 1, 0x100).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined
+ .Mine(2000, TestTime(10000), 0x100).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period
+ .Mine(2051, TestTime(10010), 0).TestStarted().TestStateSinceHeight(2000) // 51 old blocks
+ .Mine(2950, TestTime(10020), 0x100).TestStarted().TestStateSinceHeight(2000) // 899 new blocks
+ .Mine(3000, TestTime(20000), 0).TestFailed().TestStateSinceHeight(3000) // 50 old blocks (so 899 out of the past 1000)
+ .Mine(4000, TestTime(20010), 0x100).TestFailed().TestStateSinceHeight(3000)
// DEFINED -> STARTED -> FAILED while threshold reached
- .Reset().TestDefined()
- .Mine(1, TestTime(1), 0).TestDefined()
- .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined() // One second more and it would be defined
- .Mine(2000, TestTime(10000), 0x101).TestStarted() // So that's what happens the next period
- .Mine(2999, TestTime(30000), 0x100).TestStarted() // 999 new blocks
- .Mine(3000, TestTime(30000), 0x100).TestFailed() // 1 new block (so 1000 out of the past 1000 are new)
- .Mine(3999, TestTime(30001), 0).TestFailed()
- .Mine(4000, TestTime(30002), 0).TestFailed()
- .Mine(14333, TestTime(30003), 0).TestFailed()
- .Mine(24000, TestTime(40000), 0).TestFailed()
+ .Reset().TestDefined().TestStateSinceHeight(0)
+ .Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)
+ .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined
+ .Mine(2000, TestTime(10000), 0x101).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period
+ .Mine(2999, TestTime(30000), 0x100).TestStarted().TestStateSinceHeight(2000) // 999 new blocks
+ .Mine(3000, TestTime(30000), 0x100).TestFailed().TestStateSinceHeight(3000) // 1 new block (so 1000 out of the past 1000 are new)
+ .Mine(3999, TestTime(30001), 0).TestFailed().TestStateSinceHeight(3000)
+ .Mine(4000, TestTime(30002), 0).TestFailed().TestStateSinceHeight(3000)
+ .Mine(14333, TestTime(30003), 0).TestFailed().TestStateSinceHeight(3000)
+ .Mine(24000, TestTime(40000), 0).TestFailed().TestStateSinceHeight(3000)
// DEFINED -> STARTED -> LOCKEDIN at the last minute -> ACTIVE
.Reset().TestDefined()
- .Mine(1, TestTime(1), 0).TestDefined()
- .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined() // One second more and it would be defined
- .Mine(2000, TestTime(10000), 0x101).TestStarted() // So that's what happens the next period
- .Mine(2050, TestTime(10010), 0x200).TestStarted() // 50 old blocks
- .Mine(2950, TestTime(10020), 0x100).TestStarted() // 900 new blocks
- .Mine(2999, TestTime(19999), 0x200).TestStarted() // 49 old blocks
- .Mine(3000, TestTime(29999), 0x200).TestLockedIn() // 1 old block (so 900 out of the past 1000)
- .Mine(3999, TestTime(30001), 0).TestLockedIn()
- .Mine(4000, TestTime(30002), 0).TestActive()
- .Mine(14333, TestTime(30003), 0).TestActive()
- .Mine(24000, TestTime(40000), 0).TestActive();
+ .Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)
+ .Mine(1000, TestTime(10000) - 1, 0x101).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined
+ .Mine(2000, TestTime(10000), 0x101).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period
+ .Mine(2050, TestTime(10010), 0x200).TestStarted().TestStateSinceHeight(2000) // 50 old blocks
+ .Mine(2950, TestTime(10020), 0x100).TestStarted().TestStateSinceHeight(2000) // 900 new blocks
+ .Mine(2999, TestTime(19999), 0x200).TestStarted().TestStateSinceHeight(2000) // 49 old blocks
+ .Mine(3000, TestTime(29999), 0x200).TestLockedIn().TestStateSinceHeight(3000) // 1 old block (so 900 out of the past 1000)
+ .Mine(3999, TestTime(30001), 0).TestLockedIn().TestStateSinceHeight(3000)
+ .Mine(4000, TestTime(30002), 0).TestActive().TestStateSinceHeight(4000)
+ .Mine(14333, TestTime(30003), 0).TestActive().TestStateSinceHeight(4000)
+ .Mine(24000, TestTime(40000), 0).TestActive().TestStateSinceHeight(4000)
+
+ // DEFINED multiple periods -> STARTED multiple periods -> FAILED
+ .Reset().TestDefined().TestStateSinceHeight(0)
+ .Mine(999, TestTime(999), 0).TestDefined().TestStateSinceHeight(0)
+ .Mine(1000, TestTime(1000), 0).TestDefined().TestStateSinceHeight(0)
+ .Mine(2000, TestTime(2000), 0).TestDefined().TestStateSinceHeight(0)
+ .Mine(3000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)
+ .Mine(4000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)
+ .Mine(5000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)
+ .Mine(6000, TestTime(20000), 0).TestFailed().TestStateSinceHeight(6000)
+ .Mine(7000, TestTime(20000), 0x100).TestFailed().TestStateSinceHeight(6000);
}
// Sanity checks of version bit deployments
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 15fa6fbca3..0f1c166abc 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -647,7 +647,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
if (nCheckFrequency == 0)
return;
- if (insecure_rand() >= nCheckFrequency)
+ if (GetRand(std::numeric_limits<uint32_t>::max()) >= nCheckFrequency)
return;
LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size());
diff --git a/src/txmempool.h b/src/txmempool.h
index 941644b2b2..1763930ba0 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -15,6 +15,7 @@
#include "indirectmap.h"
#include "primitives/transaction.h"
#include "sync.h"
+#include "random.h"
#undef foreach
#include "boost/multi_index_container.hpp"
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index 6ddf37658d..085c336ccf 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -13,7 +13,7 @@ CMainSignals& GetMainSignals()
}
void RegisterValidationInterface(CValidationInterface* pwalletIn) {
- g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1));
+ g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3));
g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
@@ -33,7 +33,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3));
- g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1));
+ g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
}
void UnregisterAllValidationInterfaces() {
@@ -47,7 +47,3 @@ void UnregisterAllValidationInterfaces() {
g_signals.SyncTransaction.disconnect_all_slots();
g_signals.UpdatedBlockTip.disconnect_all_slots();
}
-
-void SyncWithWallets(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock) {
- g_signals.SyncTransaction(tx, pindex, posInBlock);
-}
diff --git a/src/validationinterface.h b/src/validationinterface.h
index 0c91ec8308..a29859999b 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -28,12 +28,10 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn);
void UnregisterValidationInterface(CValidationInterface* pwalletIn);
/** Unregister all wallets from core */
void UnregisterAllValidationInterfaces();
-/** Push an updated transaction to all registered wallets */
-void SyncWithWallets(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock = -1);
class CValidationInterface {
protected:
- virtual void UpdatedBlockTip(const CBlockIndex *pindex) {}
+ virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {}
virtual void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock) {}
virtual void SetBestChain(const CBlockLocator &locator) {}
virtual void UpdatedTransaction(const uint256 &hash) {}
@@ -49,7 +47,9 @@ protected:
struct CMainSignals {
/** Notifies listeners of updated block chain tip */
- boost::signals2::signal<void (const CBlockIndex *)> UpdatedBlockTip;
+ boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
+ /** A posInBlock value for SyncTransaction which indicates the transaction was conflicted, disconnected, or not in a block */
+ static const int SYNC_TRANSACTION_NOT_IN_BLOCK = -1;
/** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */
boost::signals2::signal<void (const CTransaction &, const CBlockIndex *pindex, int posInBlock)> SyncTransaction;
/** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */
diff --git a/src/versionbits.cpp b/src/versionbits.cpp
index bf32ae6627..d73f340510 100644
--- a/src/versionbits.cpp
+++ b/src/versionbits.cpp
@@ -105,6 +105,36 @@ ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex*
return state;
}
+int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
+{
+ const ThresholdState initialState = GetStateFor(pindexPrev, params, cache);
+
+ // BIP 9 about state DEFINED: "The genesis block is by definition in this state for each deployment."
+ if (initialState == THRESHOLD_DEFINED) {
+ return 0;
+ }
+
+ const int nPeriod = Period(params);
+
+ // A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
+ // To ease understanding of the following height calculation, it helps to remember that
+ // right now pindexPrev points to the block prior to the block that we are computing for, thus:
+ // if we are computing for the last block of a period, then pindexPrev points to the second to last block of the period, and
+ // if we are computing for the first block of a period, then pindexPrev points to the last block of the previous period.
+ // The parent of the genesis block is represented by NULL.
+ pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
+
+ const CBlockIndex* previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
+
+ while (previousPeriodParent != NULL && GetStateFor(previousPeriodParent, params, cache) == initialState) {
+ pindexPrev = previousPeriodParent;
+ previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
+ }
+
+ // Adjust the result because right now we point to the parent block.
+ return pindexPrev->nHeight + 1;
+}
+
namespace
{
/**
@@ -137,6 +167,11 @@ ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::
return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, cache.caches[pos]);
}
+int VersionBitsStateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache)
+{
+ return VersionBitsConditionChecker(pos).GetStateSinceHeightFor(pindexPrev, params, cache.caches[pos]);
+}
+
uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos)
{
return VersionBitsConditionChecker(pos).Mask(params);
diff --git a/src/versionbits.h b/src/versionbits.h
index ede2dcdda8..7a929266aa 100644
--- a/src/versionbits.h
+++ b/src/versionbits.h
@@ -51,8 +51,9 @@ protected:
virtual int Threshold(const Consensus::Params& params) const =0;
public:
- // Note that the function below takes a pindexPrev as input: they compute information for block B based on its parent.
+ // Note that the functions below take a pindexPrev as input: they compute information for block B based on its parent.
ThresholdState GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const;
+ int GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const;
};
struct VersionBitsCache
@@ -63,6 +64,7 @@ struct VersionBitsCache
};
ThresholdState VersionBitsState(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache);
+int VersionBitsStateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos, VersionBitsCache& cache);
uint32_t VersionBitsMask(const Consensus::Params& params, Consensus::DeploymentPos pos);
#endif
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index e80fa7dff8..8a1bbd5684 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -74,12 +74,12 @@ std::string DecodeDumpString(const std::string &str) {
return ret.str();
}
-UniValue importprivkey(const UniValue& params, bool fHelp)
+UniValue importprivkey(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() < 1 || params.size() > 3)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
throw runtime_error(
"importprivkey \"bitcoinprivkey\" ( \"label\" rescan )\n"
"\nAdds a private key (as returned by dumpprivkey) to your wallet.\n"
@@ -104,15 +104,15 @@ UniValue importprivkey(const UniValue& params, bool fHelp)
EnsureWalletIsUnlocked();
- string strSecret = params[0].get_str();
+ string strSecret = request.params[0].get_str();
string strLabel = "";
- if (params.size() > 1)
- strLabel = params[1].get_str();
+ if (request.params.size() > 1)
+ strLabel = request.params[1].get_str();
// Whether to perform rescan after import
bool fRescan = true;
- if (params.size() > 2)
- fRescan = params[2].get_bool();
+ if (request.params.size() > 2)
+ fRescan = request.params[2].get_bool();
if (fRescan && fPruneMode)
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
@@ -184,12 +184,12 @@ void ImportAddress(const CBitcoinAddress& address, const string& strLabel)
pwalletMain->SetAddressBook(address.Get(), strLabel, "receive");
}
-UniValue importaddress(const UniValue& params, bool fHelp)
+UniValue importaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() < 1 || params.size() > 4)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
throw runtime_error(
"importaddress \"address\" ( \"label\" rescan p2sh )\n"
"\nAdds a script (in hex) or address that can be watched as if it were in your wallet but cannot be used to spend.\n"
@@ -213,31 +213,31 @@ UniValue importaddress(const UniValue& params, bool fHelp)
string strLabel = "";
- if (params.size() > 1)
- strLabel = params[1].get_str();
+ if (request.params.size() > 1)
+ strLabel = request.params[1].get_str();
// Whether to perform rescan after import
bool fRescan = true;
- if (params.size() > 2)
- fRescan = params[2].get_bool();
+ if (request.params.size() > 2)
+ fRescan = request.params[2].get_bool();
if (fRescan && fPruneMode)
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
// Whether to import a p2sh version, too
bool fP2SH = false;
- if (params.size() > 3)
- fP2SH = params[3].get_bool();
+ if (request.params.size() > 3)
+ fP2SH = request.params[3].get_bool();
LOCK2(cs_main, pwalletMain->cs_wallet);
- CBitcoinAddress address(params[0].get_str());
+ CBitcoinAddress address(request.params[0].get_str());
if (address.IsValid()) {
if (fP2SH)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead");
ImportAddress(address, strLabel);
- } else if (IsHex(params[0].get_str())) {
- std::vector<unsigned char> data(ParseHex(params[0].get_str()));
+ } else if (IsHex(request.params[0].get_str())) {
+ std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
ImportScript(CScript(data.begin(), data.end()), strLabel, fP2SH);
} else {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script");
@@ -252,12 +252,12 @@ UniValue importaddress(const UniValue& params, bool fHelp)
return NullUniValue;
}
-UniValue importprunedfunds(const UniValue& params, bool fHelp)
+UniValue importprunedfunds(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() != 2)
+ if (request.fHelp || request.params.size() != 2)
throw runtime_error(
"importprunedfunds\n"
"\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n"
@@ -267,12 +267,12 @@ UniValue importprunedfunds(const UniValue& params, bool fHelp)
);
CTransaction tx;
- if (!DecodeHexTx(tx, params[0].get_str()))
+ if (!DecodeHexTx(tx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
uint256 hashTx = tx.GetHash();
CWalletTx wtx(pwalletMain,tx);
- CDataStream ssMB(ParseHexV(params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
+ CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
CMerkleBlock merkleBlock;
ssMB >> merkleBlock;
@@ -311,12 +311,12 @@ UniValue importprunedfunds(const UniValue& params, bool fHelp)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No addresses in wallet correspond to included transaction");
}
-UniValue removeprunedfunds(const UniValue& params, bool fHelp)
+UniValue removeprunedfunds(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"removeprunedfunds \"txid\"\n"
"\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will effect wallet balances.\n"
@@ -331,7 +331,7 @@ UniValue removeprunedfunds(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
uint256 hash;
- hash.SetHex(params[0].get_str());
+ hash.SetHex(request.params[0].get_str());
vector<uint256> vHash;
vHash.push_back(hash);
vector<uint256> vHashOut;
@@ -347,12 +347,12 @@ UniValue removeprunedfunds(const UniValue& params, bool fHelp)
return NullUniValue;
}
-UniValue importpubkey(const UniValue& params, bool fHelp)
+UniValue importpubkey(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() < 1 || params.size() > 4)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
throw runtime_error(
"importpubkey \"pubkey\" ( \"label\" rescan )\n"
"\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend.\n"
@@ -372,20 +372,20 @@ UniValue importpubkey(const UniValue& params, bool fHelp)
string strLabel = "";
- if (params.size() > 1)
- strLabel = params[1].get_str();
+ if (request.params.size() > 1)
+ strLabel = request.params[1].get_str();
// Whether to perform rescan after import
bool fRescan = true;
- if (params.size() > 2)
- fRescan = params[2].get_bool();
+ if (request.params.size() > 2)
+ fRescan = request.params[2].get_bool();
if (fRescan && fPruneMode)
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
- if (!IsHex(params[0].get_str()))
+ if (!IsHex(request.params[0].get_str()))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string");
- std::vector<unsigned char> data(ParseHex(params[0].get_str()));
+ std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
CPubKey pubKey(data.begin(), data.end());
if (!pubKey.IsFullyValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
@@ -405,12 +405,12 @@ UniValue importpubkey(const UniValue& params, bool fHelp)
}
-UniValue importwallet(const UniValue& params, bool fHelp)
+UniValue importwallet(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"importwallet \"filename\"\n"
"\nImports keys from a wallet dump file (see dumpwallet).\n"
@@ -433,7 +433,7 @@ UniValue importwallet(const UniValue& params, bool fHelp)
EnsureWalletIsUnlocked();
ifstream file;
- file.open(params[0].get_str().c_str(), std::ios::in | std::ios::ate);
+ file.open(request.params[0].get_str().c_str(), std::ios::in | std::ios::ate);
if (!file.is_open())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
@@ -512,12 +512,12 @@ UniValue importwallet(const UniValue& params, bool fHelp)
return NullUniValue;
}
-UniValue dumpprivkey(const UniValue& params, bool fHelp)
+UniValue dumpprivkey(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"dumpprivkey \"bitcoinaddress\"\n"
"\nReveals the private key corresponding to 'bitcoinaddress'.\n"
@@ -536,7 +536,7 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp)
EnsureWalletIsUnlocked();
- string strAddress = params[0].get_str();
+ string strAddress = request.params[0].get_str();
CBitcoinAddress address;
if (!address.SetString(strAddress))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
@@ -550,12 +550,12 @@ UniValue dumpprivkey(const UniValue& params, bool fHelp)
}
-UniValue dumpwallet(const UniValue& params, bool fHelp)
+UniValue dumpwallet(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"dumpwallet \"filename\"\n"
"\nDumps all wallet keys in a human-readable format.\n"
@@ -571,7 +571,7 @@ UniValue dumpwallet(const UniValue& params, bool fHelp)
EnsureWalletIsUnlocked();
ofstream file;
- file.open(params[0].get_str().c_str());
+ file.open(request.params[0].get_str().c_str());
if (!file.is_open())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 3eb7e5d9ba..33620aa6ff 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2010 Satoshi Nakamoto
-// Copyright (c) 2009-2015 The Bitcoin Core developers
+// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -101,12 +101,12 @@ string AccountFromValue(const UniValue& value)
return strAccount;
}
-UniValue getnewaddress(const UniValue& params, bool fHelp)
+UniValue getnewaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() > 1)
+ if (request.fHelp || request.params.size() > 1)
throw runtime_error(
"getnewaddress ( \"account\" )\n"
"\nReturns a new Bitcoin address for receiving payments.\n"
@@ -125,8 +125,8 @@ UniValue getnewaddress(const UniValue& params, bool fHelp)
// Parse the account first so we don't generate a key if there's an error
string strAccount;
- if (params.size() > 0)
- strAccount = AccountFromValue(params[0]);
+ if (request.params.size() > 0)
+ strAccount = AccountFromValue(request.params[0]);
if (!pwalletMain->IsLocked())
pwalletMain->TopUpKeyPool();
@@ -153,12 +153,12 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
return CBitcoinAddress(pubKey.GetID());
}
-UniValue getaccountaddress(const UniValue& params, bool fHelp)
+UniValue getaccountaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"getaccountaddress \"account\"\n"
"\nDEPRECATED. Returns the current Bitcoin address for receiving payments to this account.\n"
@@ -176,7 +176,7 @@ UniValue getaccountaddress(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
// Parse the account first so we don't generate a key if there's an error
- string strAccount = AccountFromValue(params[0]);
+ string strAccount = AccountFromValue(request.params[0]);
UniValue ret(UniValue::VSTR);
@@ -185,12 +185,12 @@ UniValue getaccountaddress(const UniValue& params, bool fHelp)
}
-UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
+UniValue getrawchangeaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() > 1)
+ if (request.fHelp || request.params.size() > 1)
throw runtime_error(
"getrawchangeaddress\n"
"\nReturns a new Bitcoin address, for receiving change.\n"
@@ -220,12 +220,12 @@ UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
}
-UniValue setaccount(const UniValue& params, bool fHelp)
+UniValue setaccount(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"setaccount \"bitcoinaddress\" \"account\"\n"
"\nDEPRECATED. Sets the account associated with the given address.\n"
@@ -239,13 +239,13 @@ UniValue setaccount(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- CBitcoinAddress address(params[0].get_str());
+ CBitcoinAddress address(request.params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
string strAccount;
- if (params.size() > 1)
- strAccount = AccountFromValue(params[1]);
+ if (request.params.size() > 1)
+ strAccount = AccountFromValue(request.params[1]);
// Only add the account if the address is yours.
if (IsMine(*pwalletMain, address.Get()))
@@ -266,12 +266,12 @@ UniValue setaccount(const UniValue& params, bool fHelp)
}
-UniValue getaccount(const UniValue& params, bool fHelp)
+UniValue getaccount(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"getaccount \"bitcoinaddress\"\n"
"\nDEPRECATED. Returns the account associated with the given address.\n"
@@ -286,7 +286,7 @@ UniValue getaccount(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- CBitcoinAddress address(params[0].get_str());
+ CBitcoinAddress address(request.params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
@@ -298,12 +298,12 @@ UniValue getaccount(const UniValue& params, bool fHelp)
}
-UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
+UniValue getaddressesbyaccount(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"getaddressesbyaccount \"account\"\n"
"\nDEPRECATED. Returns the list of addresses for the given account.\n"
@@ -321,7 +321,7 @@ UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- string strAccount = AccountFromValue(params[0]);
+ string strAccount = AccountFromValue(request.params[0]);
// Find all addresses that have the given account
UniValue ret(UniValue::VARR);
@@ -369,12 +369,12 @@ 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 the wallet and coins were spent in the copy but not marked as spent here.");
}
-UniValue sendtoaddress(const UniValue& params, bool fHelp)
+UniValue sendtoaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() < 2 || params.size() > 5)
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)
throw runtime_error(
"sendtoaddress \"bitcoinaddress\" amount ( \"comment\" \"comment-to\" subtractfeefromamount )\n"
"\nSend an amount to a given address.\n"
@@ -400,25 +400,25 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- CBitcoinAddress address(params[0].get_str());
+ CBitcoinAddress address(request.params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
// Amount
- CAmount nAmount = AmountFromValue(params[1]);
+ CAmount nAmount = AmountFromValue(request.params[1]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
// Wallet comments
CWalletTx wtx;
- 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].isNull() && !params[3].get_str().empty())
- wtx.mapValue["to"] = params[3].get_str();
+ if (request.params.size() > 2 && !request.params[2].isNull() && !request.params[2].get_str().empty())
+ wtx.mapValue["comment"] = request.params[2].get_str();
+ if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty())
+ wtx.mapValue["to"] = request.params[3].get_str();
bool fSubtractFeeFromAmount = false;
- if (params.size() > 4)
- fSubtractFeeFromAmount = params[4].get_bool();
+ if (request.params.size() > 4)
+ fSubtractFeeFromAmount = request.params[4].get_bool();
EnsureWalletIsUnlocked();
@@ -427,12 +427,12 @@ UniValue sendtoaddress(const UniValue& params, bool fHelp)
return wtx.GetHash().GetHex();
}
-UniValue listaddressgroupings(const UniValue& params, bool fHelp)
+UniValue listaddressgroupings(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp)
+ if (request.fHelp)
throw runtime_error(
"listaddressgroupings\n"
"\nLists groups of addresses which have had their common ownership\n"
@@ -478,12 +478,12 @@ UniValue listaddressgroupings(const UniValue& params, bool fHelp)
return jsonGroupings;
}
-UniValue signmessage(const UniValue& params, bool fHelp)
+UniValue signmessage(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() != 2)
+ if (request.fHelp || request.params.size() != 2)
throw runtime_error(
"signmessage \"bitcoinaddress\" \"message\"\n"
"\nSign a message with the private key of an address"
@@ -508,8 +508,8 @@ UniValue signmessage(const UniValue& params, bool fHelp)
EnsureWalletIsUnlocked();
- string strAddress = params[0].get_str();
- string strMessage = params[1].get_str();
+ string strAddress = request.params[0].get_str();
+ string strMessage = request.params[1].get_str();
CBitcoinAddress addr(strAddress);
if (!addr.IsValid())
@@ -534,12 +534,12 @@ UniValue signmessage(const UniValue& params, bool fHelp)
return EncodeBase64(&vchSig[0], vchSig.size());
}
-UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
+UniValue getreceivedbyaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"getreceivedbyaddress \"bitcoinaddress\" ( minconf )\n"
"\nReturns the total amount received by the given bitcoinaddress in transactions with at least minconf confirmations.\n"
@@ -562,7 +562,7 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
// Bitcoin address
- CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
+ CBitcoinAddress address = CBitcoinAddress(request.params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
CScript scriptPubKey = GetScriptForDestination(address.Get());
@@ -571,8 +571,8 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
// Minimum confirmations
int nMinDepth = 1;
- if (params.size() > 1)
- nMinDepth = params[1].get_int();
+ if (request.params.size() > 1)
+ nMinDepth = request.params[1].get_int();
// Tally
CAmount nAmount = 0;
@@ -592,12 +592,12 @@ UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
}
-UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
+UniValue getreceivedbyaccount(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"getreceivedbyaccount \"account\" ( minconf )\n"
"\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
@@ -621,11 +621,11 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
// Minimum confirmations
int nMinDepth = 1;
- if (params.size() > 1)
- nMinDepth = params[1].get_int();
+ if (request.params.size() > 1)
+ nMinDepth = request.params[1].get_int();
// Get the set of pub keys assigned to account
- string strAccount = AccountFromValue(params[0]);
+ string strAccount = AccountFromValue(request.params[0]);
set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount);
// Tally
@@ -649,12 +649,12 @@ UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
}
-UniValue getbalance(const UniValue& params, bool fHelp)
+UniValue getbalance(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() > 3)
+ if (request.fHelp || request.params.size() > 3)
throw runtime_error(
"getbalance ( \"account\" minconf includeWatchonly )\n"
"\nIf account is not specified, returns the server's total available balance.\n"
@@ -678,18 +678,18 @@ UniValue getbalance(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- if (params.size() == 0)
+ if (request.params.size() == 0)
return ValueFromAmount(pwalletMain->GetBalance());
int nMinDepth = 1;
- if (params.size() > 1)
- nMinDepth = params[1].get_int();
+ if (request.params.size() > 1)
+ nMinDepth = request.params[1].get_int();
isminefilter filter = ISMINE_SPENDABLE;
- if(params.size() > 2)
- if(params[2].get_bool())
+ if(request.params.size() > 2)
+ if(request.params[2].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
- if (params[0].get_str() == "*") {
+ if (request.params[0].get_str() == "*") {
// Calculate total balance a different way from GetBalance()
// (GetBalance() sums up all unspent TxOuts)
// getbalance and "getbalance * 1 true" should return the same number
@@ -717,19 +717,19 @@ UniValue getbalance(const UniValue& params, bool fHelp)
return ValueFromAmount(nBalance);
}
- string strAccount = AccountFromValue(params[0]);
+ string strAccount = AccountFromValue(request.params[0]);
CAmount nBalance = pwalletMain->GetAccountBalance(strAccount, nMinDepth, filter);
return ValueFromAmount(nBalance);
}
-UniValue getunconfirmedbalance(const UniValue &params, bool fHelp)
+UniValue getunconfirmedbalance(const JSONRPCRequest &request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() > 0)
+ if (request.fHelp || request.params.size() > 0)
throw runtime_error(
"getunconfirmedbalance\n"
"Returns the server's total unconfirmed balance\n");
@@ -740,12 +740,12 @@ UniValue getunconfirmedbalance(const UniValue &params, bool fHelp)
}
-UniValue movecmd(const UniValue& params, bool fHelp)
+UniValue movecmd(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() < 3 || params.size() > 5)
+ if (request.fHelp || request.params.size() < 3 || request.params.size() > 5)
throw runtime_error(
"move \"fromaccount\" \"toaccount\" amount ( minconf \"comment\" )\n"
"\nDEPRECATED. Move a specified amount from one account in your wallet to another.\n"
@@ -768,17 +768,17 @@ UniValue movecmd(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- string strFrom = AccountFromValue(params[0]);
- string strTo = AccountFromValue(params[1]);
- CAmount nAmount = AmountFromValue(params[2]);
+ string strFrom = AccountFromValue(request.params[0]);
+ string strTo = AccountFromValue(request.params[1]);
+ CAmount nAmount = AmountFromValue(request.params[2]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
- if (params.size() > 3)
+ if (request.params.size() > 3)
// unused parameter, used to be nMinDepth, keep type-checking it though
- (void)params[3].get_int();
+ (void)request.params[3].get_int();
string strComment;
- if (params.size() > 4)
- strComment = params[4].get_str();
+ if (request.params.size() > 4)
+ strComment = request.params[4].get_str();
if (!pwalletMain->AccountMove(strFrom, strTo, nAmount, strComment))
throw JSONRPCError(RPC_DATABASE_ERROR, "database error");
@@ -787,12 +787,12 @@ UniValue movecmd(const UniValue& params, bool fHelp)
}
-UniValue sendfrom(const UniValue& params, bool fHelp)
+UniValue sendfrom(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() < 3 || params.size() > 6)
+ if (request.fHelp || request.params.size() < 3 || request.params.size() > 6)
throw runtime_error(
"sendfrom \"fromaccount\" \"tobitcoinaddress\" amount ( minconf \"comment\" \"comment-to\" )\n"
"\nDEPRECATED (use sendtoaddress). Sent an amount from an account to a bitcoin address."
@@ -820,23 +820,23 @@ UniValue sendfrom(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- string strAccount = AccountFromValue(params[0]);
- CBitcoinAddress address(params[1].get_str());
+ string strAccount = AccountFromValue(request.params[0]);
+ CBitcoinAddress address(request.params[1].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
- CAmount nAmount = AmountFromValue(params[2]);
+ CAmount nAmount = AmountFromValue(request.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();
+ if (request.params.size() > 3)
+ nMinDepth = request.params[3].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
- 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].isNull() && !params[5].get_str().empty())
- wtx.mapValue["to"] = params[5].get_str();
+ if (request.params.size() > 4 && !request.params[4].isNull() && !request.params[4].get_str().empty())
+ wtx.mapValue["comment"] = request.params[4].get_str();
+ if (request.params.size() > 5 && !request.params[5].isNull() && !request.params[5].get_str().empty())
+ wtx.mapValue["to"] = request.params[5].get_str();
EnsureWalletIsUnlocked();
@@ -851,12 +851,12 @@ UniValue sendfrom(const UniValue& params, bool fHelp)
}
-UniValue sendmany(const UniValue& params, bool fHelp)
+UniValue sendmany(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() < 2 || params.size() > 5)
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 5)
throw runtime_error(
"sendmany \"fromaccount\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] )\n"
"\nSend multiple times. Amounts are double-precision floating point numbers."
@@ -897,20 +897,20 @@ UniValue sendmany(const UniValue& params, bool fHelp)
if (pwalletMain->GetBroadcastTransactions() && !g_connman)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
- string strAccount = AccountFromValue(params[0]);
- UniValue sendTo = params[1].get_obj();
+ string strAccount = AccountFromValue(request.params[0]);
+ UniValue sendTo = request.params[1].get_obj();
int nMinDepth = 1;
- if (params.size() > 2)
- nMinDepth = params[2].get_int();
+ if (request.params.size() > 2)
+ nMinDepth = request.params[2].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
- if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
- wtx.mapValue["comment"] = params[3].get_str();
+ if (request.params.size() > 3 && !request.params[3].isNull() && !request.params[3].get_str().empty())
+ wtx.mapValue["comment"] = request.params[3].get_str();
UniValue subtractFeeFromAmount(UniValue::VARR);
- if (params.size() > 4)
- subtractFeeFromAmount = params[4].get_array();
+ if (request.params.size() > 4)
+ subtractFeeFromAmount = request.params[4].get_array();
set<CBitcoinAddress> setAddress;
vector<CRecipient> vecSend;
@@ -968,12 +968,12 @@ UniValue sendmany(const UniValue& params, bool fHelp)
// Defined in rpc/misc.cpp
extern CScript _createmultisig_redeemScript(const UniValue& params);
-UniValue addmultisigaddress(const UniValue& params, bool fHelp)
+UniValue addmultisigaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() < 2 || params.size() > 3)
+ if (request.fHelp || request.params.size() < 2 || request.params.size() > 3)
{
string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" )\n"
"\nAdd a nrequired-to-sign multisignature address to the wallet.\n"
@@ -1004,11 +1004,11 @@ UniValue addmultisigaddress(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
string strAccount;
- if (params.size() > 2)
- strAccount = AccountFromValue(params[2]);
+ if (request.params.size() > 2)
+ strAccount = AccountFromValue(request.params[2]);
// Construct using pay-to-script-hash:
- CScript inner = _createmultisig_redeemScript(params);
+ CScript inner = _createmultisig_redeemScript(request.params);
CScriptID innerID(inner);
pwalletMain->AddCScript(inner);
@@ -1025,9 +1025,12 @@ public:
bool operator()(const CKeyID &keyID) {
CPubKey pubkey;
- if (pwalletMain && pwalletMain->GetPubKey(keyID, pubkey)) {
- CScript basescript;
- basescript << ToByteVector(pubkey) << OP_CHECKSIG;
+ if (pwalletMain) {
+ CScript basescript = GetScriptForDestination(keyID);
+ isminetype typ;
+ typ = IsMine(*pwalletMain, basescript, SIGVERSION_WITNESS_V0);
+ if (typ != ISMINE_SPENDABLE && typ != ISMINE_WATCH_SOLVABLE)
+ return false;
CScript witscript = GetScriptForWitness(basescript);
pwalletMain->AddCScript(witscript);
result = CScriptID(witscript);
@@ -1045,6 +1048,10 @@ public:
result = scriptID;
return true;
}
+ isminetype typ;
+ typ = IsMine(*pwalletMain, subscript, SIGVERSION_WITNESS_V0);
+ if (typ != ISMINE_SPENDABLE && typ != ISMINE_WATCH_SOLVABLE)
+ return false;
CScript witscript = GetScriptForWitness(subscript);
pwalletMain->AddCScript(witscript);
result = CScriptID(witscript);
@@ -1054,12 +1061,12 @@ public:
}
};
-UniValue addwitnessaddress(const UniValue& params, bool fHelp)
+UniValue addwitnessaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() < 1 || params.size() > 1)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 1)
{
string msg = "addwitnessaddress \"address\"\n"
"\nAdd a witness address for a script (with pubkey or redeemscript known).\n"
@@ -1082,7 +1089,7 @@ UniValue addwitnessaddress(const UniValue& params, bool fHelp)
}
}
- CBitcoinAddress address(params[0].get_str());
+ CBitcoinAddress address(request.params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
@@ -1090,7 +1097,7 @@ UniValue addwitnessaddress(const UniValue& params, bool fHelp)
CTxDestination dest = address.Get();
bool ret = boost::apply_visitor(w, dest);
if (!ret) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Public key or redeemscript not known to wallet");
+ throw JSONRPCError(RPC_WALLET_ERROR, "Public key or redeemscript not known to wallet, or the key is uncompressed");
}
pwalletMain->SetAddressBook(w.result, "", "receive");
@@ -1232,12 +1239,12 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts)
return ret;
}
-UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
+UniValue listreceivedbyaddress(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() > 3)
+ if (request.fHelp || request.params.size() > 3)
throw runtime_error(
"listreceivedbyaddress ( minconf includeempty includeWatchonly)\n"
"\nList balances by receiving address.\n"
@@ -1267,15 +1274,15 @@ UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- return ListReceived(params, false);
+ return ListReceived(request.params, false);
}
-UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
+UniValue listreceivedbyaccount(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() > 3)
+ if (request.fHelp || request.params.size() > 3)
throw runtime_error(
"listreceivedbyaccount ( minconf includeempty includeWatchonly)\n"
"\nDEPRECATED. List balances by account.\n"
@@ -1304,7 +1311,7 @@ UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- return ListReceived(params, true);
+ return ListReceived(request.params, true);
}
static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
@@ -1406,12 +1413,12 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Un
}
}
-UniValue listtransactions(const UniValue& params, bool fHelp)
+UniValue listtransactions(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() > 4)
+ if (request.fHelp || request.params.size() > 4)
throw runtime_error(
"listtransactions ( \"account\" count from includeWatchonly)\n"
"\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
@@ -1473,17 +1480,17 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
string strAccount = "*";
- if (params.size() > 0)
- strAccount = params[0].get_str();
+ if (request.params.size() > 0)
+ strAccount = request.params[0].get_str();
int nCount = 10;
- if (params.size() > 1)
- nCount = params[1].get_int();
+ if (request.params.size() > 1)
+ nCount = request.params[1].get_int();
int nFrom = 0;
- if (params.size() > 2)
- nFrom = params[2].get_int();
+ if (request.params.size() > 2)
+ nFrom = request.params[2].get_int();
isminefilter filter = ISMINE_SPENDABLE;
- if(params.size() > 3)
- if(params[3].get_bool())
+ if(request.params.size() > 3)
+ if(request.params[3].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
if (nCount < 0)
@@ -1533,12 +1540,12 @@ UniValue listtransactions(const UniValue& params, bool fHelp)
return ret;
}
-UniValue listaccounts(const UniValue& params, bool fHelp)
+UniValue listaccounts(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() > 2)
+ if (request.fHelp || request.params.size() > 2)
throw runtime_error(
"listaccounts ( minconf includeWatchonly)\n"
"\nDEPRECATED. Returns Object that has account names as keys, account balances as values.\n"
@@ -1564,11 +1571,11 @@ UniValue listaccounts(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
int nMinDepth = 1;
- if (params.size() > 0)
- nMinDepth = params[0].get_int();
+ if (request.params.size() > 0)
+ nMinDepth = request.params[0].get_int();
isminefilter includeWatchonly = ISMINE_SPENDABLE;
- if(params.size() > 1)
- if(params[1].get_bool())
+ if(request.params.size() > 1)
+ if(request.params[1].get_bool())
includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY;
map<string, CAmount> mapAccountBalances;
@@ -1612,12 +1619,12 @@ UniValue listaccounts(const UniValue& params, bool fHelp)
return ret;
}
-UniValue listsinceblock(const UniValue& params, bool fHelp)
+UniValue listsinceblock(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp)
+ if (request.fHelp)
throw runtime_error(
"listsinceblock ( \"blockhash\" target-confirmations includeWatchonly)\n"
"\nGet all transactions in blocks since block [blockhash], or all transactions if omitted\n"
@@ -1660,26 +1667,26 @@ UniValue listsinceblock(const UniValue& params, bool fHelp)
int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE;
- if (params.size() > 0)
+ if (request.params.size() > 0)
{
uint256 blockId;
- blockId.SetHex(params[0].get_str());
+ blockId.SetHex(request.params[0].get_str());
BlockMap::iterator it = mapBlockIndex.find(blockId);
if (it != mapBlockIndex.end())
pindex = it->second;
}
- if (params.size() > 1)
+ if (request.params.size() > 1)
{
- target_confirms = params[1].get_int();
+ target_confirms = request.params[1].get_int();
if (target_confirms < 1)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
}
- if(params.size() > 2)
- if(params[2].get_bool())
+ if(request.params.size() > 2)
+ if(request.params[2].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
@@ -1704,12 +1711,12 @@ UniValue listsinceblock(const UniValue& params, bool fHelp)
return ret;
}
-UniValue gettransaction(const UniValue& params, bool fHelp)
+UniValue gettransaction(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"gettransaction \"txid\" ( includeWatchonly )\n"
"\nGet detailed information about in-wallet transaction <txid>\n"
@@ -1751,11 +1758,11 @@ UniValue gettransaction(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
uint256 hash;
- hash.SetHex(params[0].get_str());
+ hash.SetHex(request.params[0].get_str());
isminefilter filter = ISMINE_SPENDABLE;
- if(params.size() > 1)
- if(params[1].get_bool())
+ if(request.params.size() > 1)
+ if(request.params[1].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
UniValue entry(UniValue::VOBJ);
@@ -1784,12 +1791,12 @@ UniValue gettransaction(const UniValue& params, bool fHelp)
return entry;
}
-UniValue abandontransaction(const UniValue& params, bool fHelp)
+UniValue abandontransaction(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"abandontransaction \"txid\"\n"
"\nMark in-wallet transaction <txid> as abandoned\n"
@@ -1808,7 +1815,7 @@ UniValue abandontransaction(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
uint256 hash;
- hash.SetHex(params[0].get_str());
+ hash.SetHex(request.params[0].get_str());
if (!pwalletMain->mapWallet.count(hash))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
@@ -1819,12 +1826,12 @@ UniValue abandontransaction(const UniValue& params, bool fHelp)
}
-UniValue backupwallet(const UniValue& params, bool fHelp)
+UniValue backupwallet(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() != 1)
+ if (request.fHelp || request.params.size() != 1)
throw runtime_error(
"backupwallet \"destination\"\n"
"\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n"
@@ -1837,7 +1844,7 @@ UniValue backupwallet(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- string strDest = params[0].get_str();
+ string strDest = request.params[0].get_str();
if (!pwalletMain->BackupWallet(strDest))
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
@@ -1845,12 +1852,12 @@ UniValue backupwallet(const UniValue& params, bool fHelp)
}
-UniValue keypoolrefill(const UniValue& params, bool fHelp)
+UniValue keypoolrefill(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() > 1)
+ if (request.fHelp || request.params.size() > 1)
throw runtime_error(
"keypoolrefill ( newsize )\n"
"\nFills the keypool."
@@ -1866,10 +1873,10 @@ UniValue keypoolrefill(const UniValue& params, bool fHelp)
// 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
unsigned int kpSize = 0;
- if (params.size() > 0) {
- if (params[0].get_int() < 0)
+ if (request.params.size() > 0) {
+ if (request.params[0].get_int() < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
- kpSize = (unsigned int)params[0].get_int();
+ kpSize = (unsigned int)request.params[0].get_int();
}
EnsureWalletIsUnlocked();
@@ -1889,12 +1896,12 @@ static void LockWallet(CWallet* pWallet)
pWallet->Lock();
}
-UniValue walletpassphrase(const UniValue& params, bool fHelp)
+UniValue walletpassphrase(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
+ if (pwalletMain->IsCrypted() && (request.fHelp || request.params.size() != 2))
throw runtime_error(
"walletpassphrase \"passphrase\" timeout\n"
"\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
@@ -1916,17 +1923,17 @@ UniValue walletpassphrase(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- if (fHelp)
+ if (request.fHelp)
return true;
if (!pwalletMain->IsCrypted())
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
- // Note that the walletpassphrase is stored in params[0] which is not mlock()ed
+ // Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed
SecureString strWalletPass;
strWalletPass.reserve(100);
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
- // Alternately, find a way to make params[0] mlock()'d to begin with.
- strWalletPass = params[0].get_str().c_str();
+ // Alternately, find a way to make request.params[0] mlock()'d to begin with.
+ strWalletPass = request.params[0].get_str().c_str();
if (strWalletPass.length() > 0)
{
@@ -1940,7 +1947,7 @@ UniValue walletpassphrase(const UniValue& params, bool fHelp)
pwalletMain->TopUpKeyPool();
- int64_t nSleepTime = params[1].get_int64();
+ int64_t nSleepTime = request.params[1].get_int64();
LOCK(cs_nWalletUnlockTime);
nWalletUnlockTime = GetTime() + nSleepTime;
RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
@@ -1949,12 +1956,12 @@ UniValue walletpassphrase(const UniValue& params, bool fHelp)
}
-UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
+UniValue walletpassphrasechange(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
+ if (pwalletMain->IsCrypted() && (request.fHelp || request.params.size() != 2))
throw runtime_error(
"walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n"
"\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n"
@@ -1968,20 +1975,20 @@ UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- if (fHelp)
+ if (request.fHelp)
return true;
if (!pwalletMain->IsCrypted())
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
// TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
- // Alternately, find a way to make params[0] mlock()'d to begin with.
+ // Alternately, find a way to make request.params[0] mlock()'d to begin with.
SecureString strOldWalletPass;
strOldWalletPass.reserve(100);
- strOldWalletPass = params[0].get_str().c_str();
+ strOldWalletPass = request.params[0].get_str().c_str();
SecureString strNewWalletPass;
strNewWalletPass.reserve(100);
- strNewWalletPass = params[1].get_str().c_str();
+ strNewWalletPass = request.params[1].get_str().c_str();
if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1)
throw runtime_error(
@@ -1995,12 +2002,12 @@ UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
}
-UniValue walletlock(const UniValue& params, bool fHelp)
+UniValue walletlock(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
+ if (pwalletMain->IsCrypted() && (request.fHelp || request.params.size() != 0))
throw runtime_error(
"walletlock\n"
"\nRemoves the wallet encryption key from memory, locking the wallet.\n"
@@ -2019,7 +2026,7 @@ UniValue walletlock(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- if (fHelp)
+ if (request.fHelp)
return true;
if (!pwalletMain->IsCrypted())
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
@@ -2034,12 +2041,12 @@ UniValue walletlock(const UniValue& params, bool fHelp)
}
-UniValue encryptwallet(const UniValue& params, bool fHelp)
+UniValue encryptwallet(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
+ if (!pwalletMain->IsCrypted() && (request.fHelp || request.params.size() != 1))
throw runtime_error(
"encryptwallet \"passphrase\"\n"
"\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
@@ -2065,16 +2072,16 @@ UniValue encryptwallet(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- if (fHelp)
+ if (request.fHelp)
return true;
if (pwalletMain->IsCrypted())
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
- // Alternately, find a way to make params[0] mlock()'d to begin with.
+ // Alternately, find a way to make request.params[0] mlock()'d to begin with.
SecureString strWalletPass;
strWalletPass.reserve(100);
- strWalletPass = params[0].get_str().c_str();
+ strWalletPass = request.params[0].get_str().c_str();
if (strWalletPass.length() < 1)
throw runtime_error(
@@ -2091,12 +2098,12 @@ UniValue encryptwallet(const UniValue& params, bool fHelp)
return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed and a new HD seed was generated (if you are using HD). You need to make a new backup.";
}
-UniValue lockunspent(const UniValue& params, bool fHelp)
+UniValue lockunspent(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"lockunspent unlock ([{\"txid\":\"txid\",\"vout\":n},...])\n"
"\nUpdates list of temporarily unspendable outputs.\n"
@@ -2135,20 +2142,20 @@ UniValue lockunspent(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- if (params.size() == 1)
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
+ if (request.params.size() == 1)
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VBOOL));
else
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
- bool fUnlock = params[0].get_bool();
+ bool fUnlock = request.params[0].get_bool();
- if (params.size() == 1) {
+ if (request.params.size() == 1) {
if (fUnlock)
pwalletMain->UnlockAllCoins();
return true;
}
- UniValue outputs = params[1].get_array();
+ UniValue outputs = request.params[1].get_array();
for (unsigned int idx = 0; idx < outputs.size(); idx++) {
const UniValue& output = outputs[idx];
if (!output.isObject())
@@ -2180,12 +2187,12 @@ UniValue lockunspent(const UniValue& params, bool fHelp)
return true;
}
-UniValue listlockunspent(const UniValue& params, bool fHelp)
+UniValue listlockunspent(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() > 0)
+ if (request.fHelp || request.params.size() > 0)
throw runtime_error(
"listlockunspent\n"
"\nReturns list of temporarily unspendable outputs.\n"
@@ -2229,12 +2236,12 @@ UniValue listlockunspent(const UniValue& params, bool fHelp)
return ret;
}
-UniValue settxfee(const UniValue& params, bool fHelp)
+UniValue settxfee(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() < 1 || params.size() > 1)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 1)
throw runtime_error(
"settxfee amount\n"
"\nSet the transaction fee per kB. Overwrites the paytxfee parameter.\n"
@@ -2250,18 +2257,18 @@ UniValue settxfee(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
// Amount
- CAmount nAmount = AmountFromValue(params[0]);
+ CAmount nAmount = AmountFromValue(request.params[0]);
payTxFee = CFeeRate(nAmount, 1000);
return true;
}
-UniValue getwalletinfo(const UniValue& params, bool fHelp)
+UniValue getwalletinfo(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"getwalletinfo\n"
"Returns an object containing various wallet state info.\n"
@@ -2302,12 +2309,12 @@ UniValue getwalletinfo(const UniValue& params, bool fHelp)
return obj;
}
-UniValue resendwallettransactions(const UniValue& params, bool fHelp)
+UniValue resendwallettransactions(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() != 0)
+ if (request.fHelp || request.params.size() != 0)
throw runtime_error(
"resendwallettransactions\n"
"Immediately re-broadcast unconfirmed wallet transactions to all peers.\n"
@@ -2330,12 +2337,12 @@ UniValue resendwallettransactions(const UniValue& params, bool fHelp)
return result;
}
-UniValue listunspent(const UniValue& params, bool fHelp)
+UniValue listunspent(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() > 3)
+ if (request.fHelp || request.params.size() > 3)
throw runtime_error(
"listunspent ( minconf maxconf [\"address\",...] )\n"
"\nReturns array of unspent transaction outputs\n"
@@ -2372,19 +2379,19 @@ UniValue listunspent(const UniValue& params, bool fHelp)
+ HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
int nMinDepth = 1;
- if (params.size() > 0)
- nMinDepth = params[0].get_int();
+ if (request.params.size() > 0)
+ nMinDepth = request.params[0].get_int();
int nMaxDepth = 9999999;
- if (params.size() > 1)
- nMaxDepth = params[1].get_int();
+ if (request.params.size() > 1)
+ nMaxDepth = request.params[1].get_int();
set<CBitcoinAddress> setAddress;
- if (params.size() > 2) {
- UniValue inputs = params[2].get_array();
+ if (request.params.size() > 2) {
+ UniValue inputs = request.params[2].get_array();
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx];
CBitcoinAddress address(input.get_str());
@@ -2441,12 +2448,12 @@ UniValue listunspent(const UniValue& params, bool fHelp)
return results;
}
-UniValue fundrawtransaction(const UniValue& params, bool fHelp)
+UniValue fundrawtransaction(const JSONRPCRequest& request)
{
- if (!EnsureWalletIsAvailable(fHelp))
+ if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue;
- if (fHelp || params.size() < 1 || params.size() > 2)
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw runtime_error(
"fundrawtransaction \"hexstring\" ( options )\n"
"\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
@@ -2487,7 +2494,7 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp)
+ HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
);
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR));
CTxDestination changeAddress = CNoDestination();
int changePosition = -1;
@@ -2496,15 +2503,15 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp)
CFeeRate feeRate = CFeeRate(0);
bool overrideEstimatedFeerate = false;
- if (params.size() > 1) {
- if (params[1].type() == UniValue::VBOOL) {
+ if (request.params.size() > 1) {
+ if (request.params[1].type() == UniValue::VBOOL) {
// backward compatibility bool only fallback
- includeWatching = params[1].get_bool();
+ includeWatching = request.params[1].get_bool();
}
else {
- RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VOBJ));
+ RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VSTR)(UniValue::VOBJ));
- UniValue options = params[1];
+ UniValue options = request.params[1];
RPCTypeCheckObj(options,
{
@@ -2544,7 +2551,7 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp)
// parse hex string from parameter
CTransaction origTx;
- if (!DecodeHexTx(origTx, params[0].get_str(), true))
+ if (!DecodeHexTx(origTx, request.params[0].get_str(), true))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
if (origTx.vout.size() == 0)
@@ -2568,14 +2575,14 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp)
return result;
}
-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 importpubkey(const UniValue& params, bool fHelp);
-extern UniValue dumpwallet(const UniValue& params, bool fHelp);
-extern UniValue importwallet(const UniValue& params, bool fHelp);
-extern UniValue importprunedfunds(const UniValue& params, bool fHelp);
-extern UniValue removeprunedfunds(const UniValue& params, bool fHelp);
+extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
+extern UniValue importprivkey(const JSONRPCRequest& request);
+extern UniValue importaddress(const JSONRPCRequest& request);
+extern UniValue importpubkey(const JSONRPCRequest& request);
+extern UniValue dumpwallet(const JSONRPCRequest& request);
+extern UniValue importwallet(const JSONRPCRequest& request);
+extern UniValue importprunedfunds(const JSONRPCRequest& request);
+extern UniValue removeprunedfunds(const JSONRPCRequest& request);
static const CRPCCommand commands[] =
{ // category name actor (function) okSafeMode
diff --git a/src/wallet/test/crypto_tests.cpp b/src/wallet/test/crypto_tests.cpp
index 05387f5f2b..c5f55ef5f0 100644
--- a/src/wallet/test/crypto_tests.cpp
+++ b/src/wallet/test/crypto_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "random.h"
+#include "test/test_random.h"
#include "utilstrencodings.h"
#include "test/test_bitcoin.h"
#include "wallet/crypter.h"
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 6f86f3360d..c7f98b238e 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1463,7 +1463,7 @@ void CWallet::ReacceptWalletTransactions()
CWalletTx& wtx = *(item.second);
LOCK(mempool.cs);
- wtx.AcceptToMemoryPool(false, maxTxFee);
+ wtx.AcceptToMemoryPool(maxTxFee);
}
}
@@ -1907,7 +1907,7 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
vfBest.assign(vValue.size(), true);
nBest = nTotalLower;
- seed_insecure_rand();
+ FastRandomContext insecure_rand;
for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)
{
@@ -1924,7 +1924,7 @@ static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,uns
//that the rng is fast. We do not use a constant random sequence,
//because there may be some privacy improvement by making
//the selection random.
- if (nPass == 0 ? insecure_rand()&1 : !vfIncluded[i])
+ if (nPass == 0 ? insecure_rand.rand32()&1 : !vfIncluded[i])
{
nTotal += vValue[i].first;
vfIncluded[i] = true;
@@ -2502,8 +2502,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey, CCon
if (fBroadcastTransactions)
{
// Broadcast
- if (!wtxNew.AcceptToMemoryPool(false, maxTxFee))
- {
+ if (!wtxNew.AcceptToMemoryPool(maxTxFee)) {
// This must not fail. The transaction has already been signed and recorded.
LogPrintf("CommitTransaction(): Error: Transaction not valid\n");
return false;
@@ -3650,8 +3649,8 @@ int CMerkleTx::GetBlocksToMaturity() const
}
-bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, CAmount nAbsurdFee)
+bool CMerkleTx::AcceptToMemoryPool(const CAmount& nAbsurdFee)
{
CValidationState state;
- return ::AcceptToMemoryPool(mempool, state, *this, fLimitFree, NULL, false, nAbsurdFee);
+ return ::AcceptToMemoryPool(mempool, state, *this, true, NULL, false, nAbsurdFee);
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 077edcab2d..3b37f7cb1f 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -215,7 +215,7 @@ public:
bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet) > 0; }
int GetBlocksToMaturity() const;
/** Pass this transaction to the mempool. Fails if absolute fee exceeds absurd fee. */
- bool AcceptToMemoryPool(bool fLimitFree, const CAmount nAbsurdFee);
+ bool AcceptToMemoryPool(const CAmount& nAbsurdFee);
bool hashUnset() const { return (hashBlock.IsNull() || hashBlock == ABANDON_HASH); }
bool isAbandoned() const { return (hashBlock == ABANDON_HASH); }
void setAbandoned() { hashBlock = ABANDON_HASH; }
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
index 376e7dec59..a0196fe184 100644
--- a/src/zmq/zmqnotificationinterface.cpp
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -124,12 +124,15 @@ void CZMQNotificationInterface::Shutdown()
}
}
-void CZMQNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindex)
+void CZMQNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
{
+ if (fInitialDownload || pindexNew == pindexFork) // In IBD or blocks were disconnected without any new ones
+ return;
+
for (std::list<CZMQAbstractNotifier*>::iterator i = notifiers.begin(); i!=notifiers.end(); )
{
CZMQAbstractNotifier *notifier = *i;
- if (notifier->NotifyBlock(pindex))
+ if (notifier->NotifyBlock(pindexNew))
{
i++;
}
diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h
index a853447267..037470ec17 100644
--- a/src/zmq/zmqnotificationinterface.h
+++ b/src/zmq/zmqnotificationinterface.h
@@ -25,7 +25,7 @@ protected:
// CValidationInterface
void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock);
- void UpdatedBlockTip(const CBlockIndex *pindex);
+ void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload);
private:
CZMQNotificationInterface();