aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.test.include7
-rw-r--r--src/core_write.cpp12
-rw-r--r--src/net_processing.cpp8
-rw-r--r--src/policy/feerate.cpp9
-rw-r--r--src/policy/feerate.h14
-rw-r--r--src/policy/fees.h7
-rw-r--r--src/pubkey.h3
-rw-r--r--src/qt/walletview.cpp4
-rw-r--r--src/rest.cpp8
-rw-r--r--src/rpc/blockchain.cpp6
-rw-r--r--src/rpc/mining.cpp2
-rw-r--r--src/rpc/misc.cpp4
-rw-r--r--src/rpc/rawtransaction.cpp4
-rw-r--r--src/rpc/rawtransaction_util.cpp4
-rw-r--r--src/rpc/util.cpp4
-rw-r--r--src/scheduler.cpp42
-rw-r--r--src/scheduler.h95
-rw-r--r--src/script/descriptor.cpp4
-rw-r--r--src/test/coins_tests.cpp2
-rw-r--r--src/test/descriptor_tests.cpp2
-rw-r--r--src/test/fuzz/crypto.cpp124
-rw-r--r--src/test/fuzz/decode_tx.cpp2
-rw-r--r--src/test/fuzz/key.cpp2
-rw-r--r--src/test/key_tests.cpp44
-rw-r--r--src/test/scheduler_tests.cpp6
-rw-r--r--src/test/sighash_tests.cpp2
-rw-r--r--src/test/util/setup_common.cpp1
-rw-r--r--src/test/util/setup_common.h1
-rw-r--r--src/util/fees.cpp40
-rw-r--r--src/util/fees.h1
-rw-r--r--src/wallet/rpcdump.cpp4
-rw-r--r--src/wallet/rpcwallet.cpp164
-rw-r--r--src/wallet/test/psbt_wallet_tests.cpp2
-rw-r--r--src/wallet/test/wallet_crypto_tests.cpp4
34 files changed, 425 insertions, 213 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 03cd9133c8..472382c7d2 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -32,6 +32,7 @@ FUZZ_TARGETS = \
test/fuzz/checkqueue \
test/fuzz/coins_deserialize \
test/fuzz/coins_view \
+ test/fuzz/crypto \
test/fuzz/crypto_common \
test/fuzz/cuckoocache \
test/fuzz/decode_tx \
@@ -479,6 +480,12 @@ test_fuzz_coins_view_LDADD = $(FUZZ_SUITE_LD_COMMON)
test_fuzz_coins_view_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
test_fuzz_coins_view_SOURCES = test/fuzz/coins_view.cpp
+test_fuzz_crypto_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
+test_fuzz_crypto_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+test_fuzz_crypto_LDADD = $(FUZZ_SUITE_LD_COMMON)
+test_fuzz_crypto_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+test_fuzz_crypto_SOURCES = test/fuzz/crypto.cpp
+
test_fuzz_crypto_common_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
test_fuzz_crypto_common_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
test_fuzz_crypto_common_LDADD = $(FUZZ_SUITE_LD_COMMON)
diff --git a/src/core_write.cpp b/src/core_write.cpp
index eb0cc35f06..429c9c5a1a 100644
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -131,13 +131,13 @@ std::string EncodeHexTx(const CTransaction& tx, const int serializeFlags)
{
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | serializeFlags);
ssTx << tx;
- return HexStr(ssTx.begin(), ssTx.end());
+ return HexStr(ssTx);
}
void ScriptToUniv(const CScript& script, UniValue& out, bool include_address)
{
out.pushKV("asm", ScriptToAsmStr(script));
- out.pushKV("hex", HexStr(script.begin(), script.end()));
+ out.pushKV("hex", HexStr(script));
std::vector<std::vector<unsigned char>> solns;
txnouttype type = Solver(script, solns);
@@ -158,7 +158,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
out.pushKV("asm", ScriptToAsmStr(scriptPubKey));
if (fIncludeHex)
- out.pushKV("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end()));
+ out.pushKV("hex", HexStr(scriptPubKey));
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired) || type == TX_PUBKEY) {
out.pushKV("type", GetTxnOutputType(type));
@@ -190,19 +190,19 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
const CTxIn& txin = tx.vin[i];
UniValue in(UniValue::VOBJ);
if (tx.IsCoinBase())
- in.pushKV("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()));
+ in.pushKV("coinbase", HexStr(txin.scriptSig));
else {
in.pushKV("txid", txin.prevout.hash.GetHex());
in.pushKV("vout", (int64_t)txin.prevout.n);
UniValue o(UniValue::VOBJ);
o.pushKV("asm", ScriptToAsmStr(txin.scriptSig, true));
- o.pushKV("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()));
+ o.pushKV("hex", HexStr(txin.scriptSig));
in.pushKV("scriptSig", o);
}
if (!tx.vin[i].scriptWitness.IsNull()) {
UniValue txinwitness(UniValue::VARR);
for (const auto& item : tx.vin[i].scriptWitness.stack) {
- txinwitness.push_back(HexStr(item.begin(), item.end()));
+ txinwitness.push_back(HexStr(item));
}
in.pushKV("txinwitness", txinwitness);
}
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 270e415e42..b5912e18a7 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -189,7 +189,7 @@ namespace {
* We use this to avoid requesting transactions that have already been
* confirnmed.
*/
- RecursiveMutex g_cs_recent_confirmed_transactions;
+ Mutex g_cs_recent_confirmed_transactions;
std::unique_ptr<CRollingBloomFilter> g_recent_confirmed_transactions GUARDED_BY(g_cs_recent_confirmed_transactions);
/** Blocks that are in flight, and that are in the queue to be downloaded. */
@@ -2454,7 +2454,7 @@ void ProcessMessage(
if (vAddr.size() > 1000)
{
LOCK(cs_main);
- Misbehaving(pfrom.GetId(), 20, strprintf("message addr size() = %u", vAddr.size()));
+ Misbehaving(pfrom.GetId(), 20, strprintf("addr message size = %u", vAddr.size()));
return;
}
@@ -2530,7 +2530,7 @@ void ProcessMessage(
if (vInv.size() > MAX_INV_SZ)
{
LOCK(cs_main);
- Misbehaving(pfrom.GetId(), 20, strprintf("message inv size() = %u", vInv.size()));
+ Misbehaving(pfrom.GetId(), 20, strprintf("inv message size = %u", vInv.size()));
return;
}
@@ -2596,7 +2596,7 @@ void ProcessMessage(
if (vInv.size() > MAX_INV_SZ)
{
LOCK(cs_main);
- Misbehaving(pfrom.GetId(), 20, strprintf("message getdata size() = %u", vInv.size()));
+ Misbehaving(pfrom.GetId(), 20, strprintf("getdata message size = %u", vInv.size()));
return;
}
diff --git a/src/policy/feerate.cpp b/src/policy/feerate.cpp
index 14be6192fe..a01e259731 100644
--- a/src/policy/feerate.cpp
+++ b/src/policy/feerate.cpp
@@ -7,8 +7,6 @@
#include <tinyformat.h>
-const std::string CURRENCY_UNIT = "BTC";
-
CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nBytes_)
{
assert(nBytes_ <= uint64_t(std::numeric_limits<int64_t>::max()));
@@ -37,7 +35,10 @@ CAmount CFeeRate::GetFee(size_t nBytes_) const
return nFee;
}
-std::string CFeeRate::ToString() const
+std::string CFeeRate::ToString(const FeeEstimateMode& fee_estimate_mode) const
{
- return strprintf("%d.%08d %s/kB", nSatoshisPerK / COIN, nSatoshisPerK % COIN, CURRENCY_UNIT);
+ switch (fee_estimate_mode) {
+ case FeeEstimateMode::SAT_B: return strprintf("%d.%03d %s/B", nSatoshisPerK / 1000, nSatoshisPerK % 1000, CURRENCY_ATOM);
+ default: return strprintf("%d.%08d %s/kB", nSatoshisPerK / COIN, nSatoshisPerK % COIN, CURRENCY_UNIT);
+ }
}
diff --git a/src/policy/feerate.h b/src/policy/feerate.h
index 61fa80c130..883940f73c 100644
--- a/src/policy/feerate.h
+++ b/src/policy/feerate.h
@@ -11,7 +11,17 @@
#include <string>
-extern const std::string CURRENCY_UNIT;
+const std::string CURRENCY_UNIT = "BTC"; // One formatted unit
+const std::string CURRENCY_ATOM = "sat"; // One indivisible minimum value unit
+
+/* Used to determine type of fee estimation requested */
+enum class FeeEstimateMode {
+ UNSET, //!< Use default settings based on other criteria
+ ECONOMICAL, //!< Force estimateSmartFee to use non-conservative estimates
+ CONSERVATIVE, //!< Force estimateSmartFee to use conservative estimates
+ BTC_KB, //!< Use explicit BTC/kB fee given in coin control
+ SAT_B, //!< Use explicit sat/B fee given in coin control
+};
/**
* Fee rate in satoshis per kilobyte: CAmount / kB
@@ -46,7 +56,7 @@ public:
friend bool operator>=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK >= b.nSatoshisPerK; }
friend bool operator!=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK != b.nSatoshisPerK; }
CFeeRate& operator+=(const CFeeRate& a) { nSatoshisPerK += a.nSatoshisPerK; return *this; }
- std::string ToString() const;
+ std::string ToString(const FeeEstimateMode& fee_estimate_mode = FeeEstimateMode::BTC_KB) const;
SERIALIZE_METHODS(CFeeRate, obj) { READWRITE(obj.nSatoshisPerK); }
};
diff --git a/src/policy/fees.h b/src/policy/fees.h
index 6ee6e0d547..e445c1590d 100644
--- a/src/policy/fees.h
+++ b/src/policy/fees.h
@@ -45,13 +45,6 @@ enum class FeeReason {
REQUIRED,
};
-/* Used to determine type of fee estimation requested */
-enum class FeeEstimateMode {
- UNSET, //!< Use default settings based on other criteria
- ECONOMICAL, //!< Force estimateSmartFee to use non-conservative estimates
- CONSERVATIVE, //!< Force estimateSmartFee to use conservative estimates
-};
-
/* Used to return detailed information about a feerate bucket */
struct EstimatorBucket
{
diff --git a/src/pubkey.h b/src/pubkey.h
index 261842b7f7..4c28af4a4d 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -142,6 +142,9 @@ public:
unsigned int len = ::ReadCompactSize(s);
if (len <= SIZE) {
s.read((char*)vch, len);
+ if (len != size()) {
+ Invalidate();
+ }
} else {
// invalid pubkey, skip available data
char dummy;
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index a3f303aea6..cec9b0eeb8 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -4,9 +4,6 @@
#include <qt/walletview.h>
-#include <node/psbt.h>
-#include <node/transaction.h>
-#include <policy/policy.h>
#include <qt/addressbookpage.h>
#include <qt/askpassphrasedialog.h>
#include <qt/clientmodel.h>
@@ -23,6 +20,7 @@
#include <qt/walletmodel.h>
#include <interfaces/node.h>
+#include <psbt.h>
#include <ui_interface.h>
#include <util/strencodings.h>
diff --git a/src/rest.cpp b/src/rest.cpp
index cde8b472d3..8cb594a03b 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -188,7 +188,7 @@ static bool rest_headers(const util::Ref& context,
ssHeader << pindex->GetBlockHeader();
}
- std::string strHex = HexStr(ssHeader.begin(), ssHeader.end()) + "\n";
+ std::string strHex = HexStr(ssHeader) + "\n";
req->WriteHeader("Content-Type", "text/plain");
req->WriteReply(HTTP_OK, strHex);
return true;
@@ -253,7 +253,7 @@ static bool rest_block(HTTPRequest* req,
case RetFormat::HEX: {
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
ssBlock << block;
- std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()) + "\n";
+ std::string strHex = HexStr(ssBlock) + "\n";
req->WriteHeader("Content-Type", "text/plain");
req->WriteReply(HTTP_OK, strHex);
return true;
@@ -391,7 +391,7 @@ static bool rest_tx(const util::Ref& context, HTTPRequest* req, const std::strin
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
ssTx << tx;
- std::string strHex = HexStr(ssTx.begin(), ssTx.end()) + "\n";
+ std::string strHex = HexStr(ssTx) + "\n";
req->WriteHeader("Content-Type", "text/plain");
req->WriteReply(HTTP_OK, strHex);
return true;
@@ -556,7 +556,7 @@ static bool rest_getutxos(const util::Ref& context, HTTPRequest* req, const std:
case RetFormat::HEX: {
CDataStream ssGetUTXOResponse(SER_NETWORK, PROTOCOL_VERSION);
ssGetUTXOResponse << ::ChainActive().Height() << ::ChainActive().Tip()->GetBlockHash() << bitmap << outs;
- std::string strHex = HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) + "\n";
+ std::string strHex = HexStr(ssGetUTXOResponse) + "\n";
req->WriteHeader("Content-Type", "text/plain");
req->WriteReply(HTTP_OK, strHex);
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 8252af3ee6..64f8a5bb3b 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -779,7 +779,7 @@ static UniValue getblockheader(const JSONRPCRequest& request)
{
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
ssBlock << pblockindex->GetBlockHeader();
- std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
+ std::string strHex = HexStr(ssBlock);
return strHex;
}
@@ -905,7 +905,7 @@ static UniValue getblock(const JSONRPCRequest& request)
{
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
ssBlock << block;
- std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
+ std::string strHex = HexStr(ssBlock);
return strHex;
}
@@ -2159,7 +2159,7 @@ UniValue scantxoutset(const JSONRPCRequest& request)
UniValue unspent(UniValue::VOBJ);
unspent.pushKV("txid", outpoint.hash.GetHex());
unspent.pushKV("vout", (int32_t)outpoint.n);
- unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey.begin(), txo.scriptPubKey.end()));
+ unspent.pushKV("scriptPubKey", HexStr(txo.scriptPubKey));
unspent.pushKV("desc", descriptors[txo.scriptPubKey]);
unspent.pushKV("amount", ValueFromAmount(txo.nValue));
unspent.pushKV("height", (int32_t)coin.nHeight);
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index e8e0ab3179..fee6a893eb 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -873,7 +873,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
result.pushKV("height", (int64_t)(pindexPrev->nHeight+1));
if (!pblocktemplate->vchCoinbaseCommitment.empty()) {
- result.pushKV("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment.begin(), pblocktemplate->vchCoinbaseCommitment.end()));
+ result.pushKV("default_witness_commitment", HexStr(pblocktemplate->vchCoinbaseCommitment));
}
return result;
diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp
index ce98a7c937..53d38f4e11 100644
--- a/src/rpc/misc.cpp
+++ b/src/rpc/misc.cpp
@@ -63,7 +63,7 @@ static UniValue validateaddress(const JSONRPCRequest& request)
ret.pushKV("address", currentAddress);
CScript scriptPubKey = GetScriptForDestination(dest);
- ret.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()));
+ ret.pushKV("scriptPubKey", HexStr(scriptPubKey));
UniValue detail = DescribeAddress(dest);
ret.pushKVs(detail);
@@ -131,7 +131,7 @@ static UniValue createmultisig(const JSONRPCRequest& request)
UniValue result(UniValue::VOBJ);
result.pushKV("address", EncodeDestination(dest));
- result.pushKV("redeemScript", HexStr(inner.begin(), inner.end()));
+ result.pushKV("redeemScript", HexStr(inner));
result.pushKV("descriptor", descriptor->ToString());
return result;
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 814f8bddfe..a53b91c4bc 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -305,7 +305,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
CDataStream ssMB(SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
CMerkleBlock mb(block, setTxids);
ssMB << mb;
- std::string strHex = HexStr(ssMB.begin(), ssMB.end());
+ std::string strHex = HexStr(ssMB);
return strHex;
}
@@ -1186,7 +1186,7 @@ UniValue decodepsbt(const JSONRPCRequest& request)
if (!input.final_script_witness.IsNull()) {
UniValue txinwitness(UniValue::VARR);
for (const auto& item : input.final_script_witness.stack) {
- txinwitness.push_back(HexStr(item.begin(), item.end()));
+ txinwitness.push_back(HexStr(item));
}
in.pushKV("final_scriptwitness", txinwitness);
}
diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp
index bd82773bf2..1031716b4a 100644
--- a/src/rpc/rawtransaction_util.cpp
+++ b/src/rpc/rawtransaction_util.cpp
@@ -138,10 +138,10 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::
entry.pushKV("vout", (uint64_t)txin.prevout.n);
UniValue witness(UniValue::VARR);
for (unsigned int i = 0; i < txin.scriptWitness.stack.size(); i++) {
- witness.push_back(HexStr(txin.scriptWitness.stack[i].begin(), txin.scriptWitness.stack[i].end()));
+ witness.push_back(HexStr(txin.scriptWitness.stack[i]));
}
entry.pushKV("witness", witness);
- entry.pushKV("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()));
+ entry.pushKV("scriptSig", HexStr(txin.scriptSig));
entry.pushKV("sequence", (uint64_t)txin.nSequence);
entry.pushKV("error", strMessage);
vErrorsRet.push_back(entry);
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index e7afef4cac..54ea352a72 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -224,7 +224,7 @@ public:
obj.pushKV("isscript", false);
obj.pushKV("iswitness", true);
obj.pushKV("witness_version", 0);
- obj.pushKV("witness_program", HexStr(id.begin(), id.end()));
+ obj.pushKV("witness_program", HexStr(id));
return obj;
}
@@ -234,7 +234,7 @@ public:
obj.pushKV("isscript", true);
obj.pushKV("iswitness", true);
obj.pushKV("witness_version", 0);
- obj.pushKV("witness_program", HexStr(id.begin(), id.end()));
+ obj.pushKV("witness_program", HexStr(id));
return obj;
}
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
index c4bd47310b..7c361bf26f 100644
--- a/src/scheduler.cpp
+++ b/src/scheduler.cpp
@@ -30,9 +30,6 @@ void CScheduler::serviceQueue()
// is called.
while (!shouldStop()) {
try {
- if (!shouldStop() && taskQueue.empty()) {
- REVERSE_LOCK(lock);
- }
while (!shouldStop() && taskQueue.empty()) {
// Wait until there is something to do.
newTaskScheduled.wait(lock);
@@ -71,18 +68,6 @@ void CScheduler::serviceQueue()
newTaskScheduled.notify_one();
}
-void CScheduler::stop(bool drain)
-{
- {
- LOCK(newTaskMutex);
- if (drain)
- stopWhenEmpty = true;
- else
- stopRequested = true;
- }
- newTaskScheduled.notify_all();
-}
-
void CScheduler::schedule(CScheduler::Function f, std::chrono::system_clock::time_point t)
{
{
@@ -125,8 +110,8 @@ void CScheduler::scheduleEvery(CScheduler::Function f, std::chrono::milliseconds
scheduleFromNow([=] { Repeat(*this, f, delta); }, delta);
}
-size_t CScheduler::getQueueInfo(std::chrono::system_clock::time_point &first,
- std::chrono::system_clock::time_point &last) const
+size_t CScheduler::getQueueInfo(std::chrono::system_clock::time_point& first,
+ std::chrono::system_clock::time_point& last) const
{
LOCK(newTaskMutex);
size_t result = taskQueue.size();
@@ -137,13 +122,15 @@ size_t CScheduler::getQueueInfo(std::chrono::system_clock::time_point &first,
return result;
}
-bool CScheduler::AreThreadsServicingQueue() const {
+bool CScheduler::AreThreadsServicingQueue() const
+{
LOCK(newTaskMutex);
return nThreadsServicingQueue;
}
-void SingleThreadedSchedulerClient::MaybeScheduleProcessQueue() {
+void SingleThreadedSchedulerClient::MaybeScheduleProcessQueue()
+{
{
LOCK(m_cs_callbacks_pending);
// Try to avoid scheduling too many copies here, but if we
@@ -155,8 +142,9 @@ void SingleThreadedSchedulerClient::MaybeScheduleProcessQueue() {
m_pscheduler->schedule(std::bind(&SingleThreadedSchedulerClient::ProcessQueue, this), std::chrono::system_clock::now());
}
-void SingleThreadedSchedulerClient::ProcessQueue() {
- std::function<void ()> callback;
+void SingleThreadedSchedulerClient::ProcessQueue()
+{
+ std::function<void()> callback;
{
LOCK(m_cs_callbacks_pending);
if (m_are_callbacks_running) return;
@@ -172,7 +160,8 @@ void SingleThreadedSchedulerClient::ProcessQueue() {
struct RAIICallbacksRunning {
SingleThreadedSchedulerClient* instance;
explicit RAIICallbacksRunning(SingleThreadedSchedulerClient* _instance) : instance(_instance) {}
- ~RAIICallbacksRunning() {
+ ~RAIICallbacksRunning()
+ {
{
LOCK(instance->m_cs_callbacks_pending);
instance->m_are_callbacks_running = false;
@@ -184,7 +173,8 @@ void SingleThreadedSchedulerClient::ProcessQueue() {
callback();
}
-void SingleThreadedSchedulerClient::AddToProcessQueue(std::function<void ()> func) {
+void SingleThreadedSchedulerClient::AddToProcessQueue(std::function<void()> func)
+{
assert(m_pscheduler);
{
@@ -194,7 +184,8 @@ void SingleThreadedSchedulerClient::AddToProcessQueue(std::function<void ()> fun
MaybeScheduleProcessQueue();
}
-void SingleThreadedSchedulerClient::EmptyQueue() {
+void SingleThreadedSchedulerClient::EmptyQueue()
+{
assert(!m_pscheduler->AreThreadsServicingQueue());
bool should_continue = true;
while (should_continue) {
@@ -204,7 +195,8 @@ void SingleThreadedSchedulerClient::EmptyQueue() {
}
}
-size_t SingleThreadedSchedulerClient::CallbacksPending() {
+size_t SingleThreadedSchedulerClient::CallbacksPending()
+{
LOCK(m_cs_callbacks_pending);
return m_callbacks_pending.size();
}
diff --git a/src/scheduler.h b/src/scheduler.h
index 1e64195484..d7fe00d1b4 100644
--- a/src/scheduler.h
+++ b/src/scheduler.h
@@ -5,11 +5,6 @@
#ifndef BITCOIN_SCHEDULER_H
#define BITCOIN_SCHEDULER_H
-//
-// NOTE:
-// boost::thread should be ported to std::thread
-// when we support C++11.
-//
#include <condition_variable>
#include <functional>
#include <list>
@@ -17,24 +12,23 @@
#include <sync.h>
-//
-// Simple class for background tasks that should be run
-// periodically or once "after a while"
-//
-// Usage:
-//
-// CScheduler* s = new CScheduler();
-// s->scheduleFromNow(doSomething, std::chrono::milliseconds{11}); // Assuming a: void doSomething() { }
-// s->scheduleFromNow([=] { this->func(argument); }, std::chrono::milliseconds{3});
-// boost::thread* t = new boost::thread(std::bind(CScheduler::serviceQueue, s));
-//
-// ... then at program shutdown, make sure to call stop() to clean up the thread(s) running serviceQueue:
-// s->stop();
-// t->join();
-// delete t;
-// delete s; // Must be done after thread is interrupted/joined.
-//
-
+/**
+ * Simple class for background tasks that should be run
+ * periodically or once "after a while"
+ *
+ * Usage:
+ *
+ * CScheduler* s = new CScheduler();
+ * s->scheduleFromNow(doSomething, std::chrono::milliseconds{11}); // Assuming a: void doSomething() { }
+ * s->scheduleFromNow([=] { this->func(argument); }, std::chrono::milliseconds{3});
+ * std::thread* t = new std::thread([&] { s->serviceQueue(); });
+ *
+ * ... then at program shutdown, make sure to call stop() to clean up the thread(s) running serviceQueue:
+ * s->stop();
+ * t->join();
+ * delete t;
+ * delete s; // Must be done after thread is interrupted/joined.
+ */
class CScheduler
{
public:
@@ -43,7 +37,7 @@ public:
typedef std::function<void()> Function;
- // Call func at/after time t
+ /** Call func at/after time t */
void schedule(Function f, std::chrono::system_clock::time_point t);
/** Call f once after the delta has passed */
@@ -67,23 +61,33 @@ public:
*/
void MockForward(std::chrono::seconds delta_seconds);
- // To keep things as simple as possible, there is no unschedule.
-
- // Services the queue 'forever'. Should be run in a thread,
- // and interrupted using boost::interrupt_thread
+ /**
+ * Services the queue 'forever'. Should be run in a thread,
+ * and interrupted using boost::interrupt_thread
+ */
void serviceQueue();
- // Tell any threads running serviceQueue to stop as soon as they're
- // done servicing whatever task they're currently servicing (drain=false)
- // or when there is no work left to be done (drain=true)
- void stop(bool drain=false);
+ /** Tell any threads running serviceQueue to stop as soon as the current task is done */
+ void stop()
+ {
+ WITH_LOCK(newTaskMutex, stopRequested = true);
+ newTaskScheduled.notify_all();
+ }
+ /** Tell any threads running serviceQueue to stop when there is no work left to be done */
+ void StopWhenDrained()
+ {
+ WITH_LOCK(newTaskMutex, stopWhenEmpty = true);
+ newTaskScheduled.notify_all();
+ }
- // Returns number of tasks waiting to be serviced,
- // and first and last task times
- size_t getQueueInfo(std::chrono::system_clock::time_point &first,
- std::chrono::system_clock::time_point &last) const;
+ /**
+ * Returns number of tasks waiting to be serviced,
+ * and first and last task times
+ */
+ size_t getQueueInfo(std::chrono::system_clock::time_point& first,
+ std::chrono::system_clock::time_point& last) const;
- // Returns true if there are threads actively running in serviceQueue()
+ /** Returns true if there are threads actively running in serviceQueue() */
bool AreThreadsServicingQueue() const;
private:
@@ -106,19 +110,20 @@ private:
* B() will be able to observe all of the effects of callback A() which executed
* before it.
*/
-class SingleThreadedSchedulerClient {
+class SingleThreadedSchedulerClient
+{
private:
- CScheduler *m_pscheduler;
+ CScheduler* m_pscheduler;
RecursiveMutex m_cs_callbacks_pending;
- std::list<std::function<void ()>> m_callbacks_pending GUARDED_BY(m_cs_callbacks_pending);
+ std::list<std::function<void()>> m_callbacks_pending GUARDED_BY(m_cs_callbacks_pending);
bool m_are_callbacks_running GUARDED_BY(m_cs_callbacks_pending) = false;
void MaybeScheduleProcessQueue();
void ProcessQueue();
public:
- explicit SingleThreadedSchedulerClient(CScheduler *pschedulerIn) : m_pscheduler(pschedulerIn) {}
+ explicit SingleThreadedSchedulerClient(CScheduler* pschedulerIn) : m_pscheduler(pschedulerIn) {}
/**
* Add a callback to be executed. Callbacks are executed serially
@@ -126,10 +131,12 @@ public:
* Practically, this means that callbacks can behave as if they are executed
* in order by a single thread.
*/
- void AddToProcessQueue(std::function<void ()> func);
+ void AddToProcessQueue(std::function<void()> func);
- // Processes all remaining queue members on the calling thread, blocking until queue is empty
- // Must be called after the CScheduler has no remaining processing threads!
+ /**
+ * Processes all remaining queue members on the calling thread, blocking until queue is empty
+ * Must be called after the CScheduler has no remaining processing threads!
+ */
void EmptyQueue();
size_t CallbacksPending();
diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp
index 7a5421ab6f..2634d3ad4f 100644
--- a/src/script/descriptor.cpp
+++ b/src/script/descriptor.cpp
@@ -235,7 +235,7 @@ public:
}
bool IsRange() const override { return false; }
size_t GetSize() const override { return m_pubkey.size(); }
- std::string ToString() const override { return HexStr(m_pubkey.begin(), m_pubkey.end()); }
+ std::string ToString() const override { return HexStr(m_pubkey); }
bool ToPrivateString(const SigningProvider& arg, std::string& ret) const override
{
CKey key;
@@ -583,7 +583,7 @@ class RawDescriptor final : public DescriptorImpl
{
const CScript m_script;
protected:
- std::string ToStringExtra() const override { return HexStr(m_script.begin(), m_script.end()); }
+ std::string ToStringExtra() const override { return HexStr(m_script); }
std::vector<CScript> MakeScripts(const std::vector<CPubKey>&, const CScript*, FlatSigningProvider&) const override { return Vector(m_script); }
public:
RawDescriptor(CScript script) : DescriptorImpl({}, {}, "raw"), m_script(std::move(script)) {}
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 60196c36a5..173ec5e3d9 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -538,7 +538,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
CDataStream tmp(SER_DISK, CLIENT_VERSION);
uint64_t x = 3000000000ULL;
tmp << VARINT(x);
- BOOST_CHECK_EQUAL(HexStr(tmp.begin(), tmp.end()), "8a95c0bb00");
+ BOOST_CHECK_EQUAL(HexStr(tmp), "8a95c0bb00");
CDataStream ss5(ParseHex("00008a95c0bb00"), SER_DISK, CLIENT_VERSION);
try {
Coin cc5;
diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp
index 5f9a78ceb2..5d7065dafb 100644
--- a/src/test/descriptor_tests.cpp
+++ b/src/test/descriptor_tests.cpp
@@ -216,7 +216,7 @@ void DoCheck(const std::string& prv, const std::string& pub, int flags, const st
// For each of the produced scripts, verify solvability, and when possible, try to sign a transaction spending it.
for (size_t n = 0; n < spks.size(); ++n) {
- BOOST_CHECK_EQUAL(ref[n], HexStr(spks[n].begin(), spks[n].end()));
+ BOOST_CHECK_EQUAL(ref[n], HexStr(spks[n]));
BOOST_CHECK_EQUAL(IsSolvable(Merge(key_provider, script_provider), spks[n]), (flags & UNSOLVABLE) == 0);
if (flags & SIGNABLE) {
diff --git a/src/test/fuzz/crypto.cpp b/src/test/fuzz/crypto.cpp
new file mode 100644
index 0000000000..595cdf9abb
--- /dev/null
+++ b/src/test/fuzz/crypto.cpp
@@ -0,0 +1,124 @@
+// Copyright (c) 2020 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 <crypto/hmac_sha256.h>
+#include <crypto/hmac_sha512.h>
+#include <crypto/ripemd160.h>
+#include <crypto/sha1.h>
+#include <crypto/sha256.h>
+#include <crypto/sha512.h>
+#include <hash.h>
+#include <test/fuzz/FuzzedDataProvider.h>
+#include <test/fuzz/fuzz.h>
+#include <test/fuzz/util.h>
+
+#include <cstdint>
+#include <vector>
+
+void test_one_input(const std::vector<uint8_t>& buffer)
+{
+ FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
+ std::vector<uint8_t> data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ if (data.empty()) {
+ data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>());
+ }
+
+ CHash160 hash160;
+ CHash256 hash256;
+ CHMAC_SHA256 hmac_sha256{data.data(), data.size()};
+ CHMAC_SHA512 hmac_sha512{data.data(), data.size()};
+ CRIPEMD160 ripemd160;
+ CSHA1 sha1;
+ CSHA256 sha256;
+ CSHA512 sha512;
+ CSipHasher sip_hasher{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>()};
+
+ while (fuzzed_data_provider.ConsumeBool()) {
+ switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 2)) {
+ case 0: {
+ if (fuzzed_data_provider.ConsumeBool()) {
+ data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
+ if (data.empty()) {
+ data.resize(fuzzed_data_provider.ConsumeIntegralInRange<size_t>(1, 4096), fuzzed_data_provider.ConsumeIntegral<uint8_t>());
+ }
+ }
+
+ (void)hash160.Write(data.data(), data.size());
+ (void)hash256.Write(data.data(), data.size());
+ (void)hmac_sha256.Write(data.data(), data.size());
+ (void)hmac_sha512.Write(data.data(), data.size());
+ (void)ripemd160.Write(data.data(), data.size());
+ (void)sha1.Write(data.data(), data.size());
+ (void)sha256.Write(data.data(), data.size());
+ (void)sha512.Write(data.data(), data.size());
+ (void)sip_hasher.Write(data.data(), data.size());
+
+ (void)Hash(data.begin(), data.end());
+ (void)Hash160(data);
+ (void)Hash160(data.begin(), data.end());
+ (void)sha512.Size();
+ break;
+ }
+ case 1: {
+ (void)hash160.Reset();
+ (void)hash256.Reset();
+ (void)ripemd160.Reset();
+ (void)sha1.Reset();
+ (void)sha256.Reset();
+ (void)sha512.Reset();
+ break;
+ }
+ case 2: {
+ switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 8)) {
+ case 0: {
+ data.resize(CHash160::OUTPUT_SIZE);
+ hash160.Finalize(data.data());
+ break;
+ }
+ case 1: {
+ data.resize(CHash256::OUTPUT_SIZE);
+ hash256.Finalize(data.data());
+ break;
+ }
+ case 2: {
+ data.resize(CHMAC_SHA256::OUTPUT_SIZE);
+ hmac_sha256.Finalize(data.data());
+ break;
+ }
+ case 3: {
+ data.resize(CHMAC_SHA512::OUTPUT_SIZE);
+ hmac_sha512.Finalize(data.data());
+ break;
+ }
+ case 4: {
+ data.resize(CRIPEMD160::OUTPUT_SIZE);
+ ripemd160.Finalize(data.data());
+ break;
+ }
+ case 5: {
+ data.resize(CSHA1::OUTPUT_SIZE);
+ sha1.Finalize(data.data());
+ break;
+ }
+ case 6: {
+ data.resize(CSHA256::OUTPUT_SIZE);
+ sha256.Finalize(data.data());
+ break;
+ }
+ case 7: {
+ data.resize(CSHA512::OUTPUT_SIZE);
+ sha512.Finalize(data.data());
+ break;
+ }
+ case 8: {
+ data.resize(1);
+ data[0] = sip_hasher.Finalize() % 256;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/src/test/fuzz/decode_tx.cpp b/src/test/fuzz/decode_tx.cpp
index 09c4ff05df..0d89d4228a 100644
--- a/src/test/fuzz/decode_tx.cpp
+++ b/src/test/fuzz/decode_tx.cpp
@@ -14,7 +14,7 @@
void test_one_input(const std::vector<uint8_t>& buffer)
{
- const std::string tx_hex = HexStr(std::string{buffer.begin(), buffer.end()});
+ const std::string tx_hex = HexStr(buffer);
CMutableTransaction mtx;
const bool result_none = DecodeHexTx(mtx, tx_hex, false, false);
const bool result_try_witness = DecodeHexTx(mtx, tx_hex, false, true);
diff --git a/src/test/fuzz/key.cpp b/src/test/fuzz/key.cpp
index 1919a5f881..58735545c9 100644
--- a/src/test/fuzz/key.cpp
+++ b/src/test/fuzz/key.cpp
@@ -108,7 +108,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
assert(pubkey.IsCompressed());
assert(pubkey.IsValid());
assert(pubkey.IsFullyValid());
- assert(HexToPubKey(HexStr(pubkey.begin(), pubkey.end())) == pubkey);
+ assert(HexToPubKey(HexStr(pubkey)) == pubkey);
assert(GetAllDestinationsForKey(pubkey).size() == 3);
}
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index cf2bd03698..fd35537c77 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -5,6 +5,7 @@
#include <key.h>
#include <key_io.h>
+#include <streams.h>
#include <test/util/setup_common.h>
#include <uint256.h>
#include <util/strencodings.h>
@@ -220,4 +221,47 @@ BOOST_AUTO_TEST_CASE(key_key_negation)
BOOST_CHECK(key.GetPubKey().data()[0] == 0x03);
}
+static CPubKey UnserializePubkey(const std::vector<uint8_t>& data)
+{
+ CDataStream stream{SER_NETWORK, INIT_PROTO_VERSION};
+ stream << data;
+ CPubKey pubkey;
+ stream >> pubkey;
+ return pubkey;
+}
+
+static unsigned int GetLen(unsigned char chHeader)
+{
+ if (chHeader == 2 || chHeader == 3)
+ return CPubKey::COMPRESSED_SIZE;
+ if (chHeader == 4 || chHeader == 6 || chHeader == 7)
+ return CPubKey::SIZE;
+ return 0;
+}
+
+static void CmpSerializationPubkey(const CPubKey& pubkey)
+{
+ CDataStream stream{SER_NETWORK, INIT_PROTO_VERSION};
+ stream << pubkey;
+ CPubKey pubkey2;
+ stream >> pubkey2;
+ BOOST_CHECK(pubkey == pubkey2);
+}
+
+BOOST_AUTO_TEST_CASE(pubkey_unserialize)
+{
+ for (uint8_t i = 2; i <= 7; ++i) {
+ CPubKey key = UnserializePubkey({0x02});
+ BOOST_CHECK(!key.IsValid());
+ CmpSerializationPubkey(key);
+ key = UnserializePubkey(std::vector<uint8_t>(GetLen(i), i));
+ CmpSerializationPubkey(key);
+ if (i == 5) {
+ BOOST_CHECK(!key.IsValid());
+ } else {
+ BOOST_CHECK(key.IsValid());
+ }
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index fcee6a9b9d..2e5a7549b7 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -89,7 +89,7 @@ BOOST_AUTO_TEST_CASE(manythreads)
}
// Drain the task queue then exit threads
- microTasks.stop(true);
+ microTasks.StopWhenDrained();
microThreads.join_all(); // ... wait until all the threads are done
int counterSum = 0;
@@ -155,7 +155,7 @@ BOOST_AUTO_TEST_CASE(singlethreadedscheduler_ordered)
}
// finish up
- scheduler.stop(true);
+ scheduler.StopWhenDrained();
threads.join_all();
BOOST_CHECK_EQUAL(counter1, 100);
@@ -186,7 +186,7 @@ BOOST_AUTO_TEST_CASE(mockforward)
scheduler.MockForward(std::chrono::minutes{5});
// ensure scheduler has chance to process all tasks queued for before 1 ms from now.
- scheduler.scheduleFromNow([&scheduler] { scheduler.stop(false); }, std::chrono::milliseconds{1});
+ scheduler.scheduleFromNow([&scheduler] { scheduler.stop(); }, std::chrono::milliseconds{1});
scheduler_thread.join();
// check that the queue only has one job remaining
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index 5ca136ea6e..c0bb92258b 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -141,7 +141,7 @@ BOOST_AUTO_TEST_CASE(sighash_test)
ss << txTo;
std::cout << "\t[\"" ;
- std::cout << HexStr(ss.begin(), ss.end()) << "\", \"";
+ std::cout << HexStr(ss) << "\", \"";
std::cout << HexStr(scriptCode) << "\", ";
std::cout << nIn << ", ";
std::cout << nHashType << ", \"";
diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp
index 3b7a7c8d12..709d357b8a 100644
--- a/src/test/util/setup_common.cpp
+++ b/src/test/util/setup_common.cpp
@@ -19,6 +19,7 @@
#include <rpc/blockchain.h>
#include <rpc/register.h>
#include <rpc/server.h>
+#include <scheduler.h>
#include <script/sigcache.h>
#include <streams.h>
#include <txdb.h>
diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h
index d5cda8a95b..e480782c12 100644
--- a/src/test/util/setup_common.h
+++ b/src/test/util/setup_common.h
@@ -11,7 +11,6 @@
#include <node/context.h>
#include <pubkey.h>
#include <random.h>
-#include <scheduler.h>
#include <txmempool.h>
#include <util/string.h>
diff --git a/src/util/fees.cpp b/src/util/fees.cpp
index b335bfa666..6208a20a97 100644
--- a/src/util/fees.cpp
+++ b/src/util/fees.cpp
@@ -6,11 +6,16 @@
#include <util/fees.h>
#include <policy/fees.h>
+#include <util/strencodings.h>
+#include <util/string.h>
#include <map>
#include <string>
+#include <vector>
+#include <utility>
-std::string StringForFeeReason(FeeReason reason) {
+std::string StringForFeeReason(FeeReason reason)
+{
static const std::map<FeeReason, std::string> fee_reason_strings = {
{FeeReason::NONE, "None"},
{FeeReason::HALF_ESTIMATE, "Half Target 60% Threshold"},
@@ -29,16 +34,31 @@ std::string StringForFeeReason(FeeReason reason) {
return reason_string->second;
}
-bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode) {
- static const std::map<std::string, FeeEstimateMode> fee_modes = {
- {"UNSET", FeeEstimateMode::UNSET},
- {"ECONOMICAL", FeeEstimateMode::ECONOMICAL},
- {"CONSERVATIVE", FeeEstimateMode::CONSERVATIVE},
+const std::vector<std::pair<std::string, FeeEstimateMode>>& FeeModeMap()
+{
+ static const std::vector<std::pair<std::string, FeeEstimateMode>> FEE_MODES = {
+ {"unset", FeeEstimateMode::UNSET},
+ {"economical", FeeEstimateMode::ECONOMICAL},
+ {"conservative", FeeEstimateMode::CONSERVATIVE},
+ {(CURRENCY_UNIT + "/kB"), FeeEstimateMode::BTC_KB},
+ {(CURRENCY_ATOM + "/B"), FeeEstimateMode::SAT_B},
};
- auto mode = fee_modes.find(mode_string);
+ return FEE_MODES;
+}
- if (mode == fee_modes.end()) return false;
+std::string FeeModes(const std::string& delimiter)
+{
+ return Join(FeeModeMap(), delimiter, [&](const std::pair<std::string, FeeEstimateMode>& i) { return i.first; });
+}
- fee_estimate_mode = mode->second;
- return true;
+bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode)
+{
+ auto searchkey = ToUpper(mode_string);
+ for (const auto& pair : FeeModeMap()) {
+ if (ToUpper(pair.first) == searchkey) {
+ fee_estimate_mode = pair.second;
+ return true;
+ }
+ }
+ return false;
}
diff --git a/src/util/fees.h b/src/util/fees.h
index a930c8935a..d52046a44c 100644
--- a/src/util/fees.h
+++ b/src/util/fees.h
@@ -12,5 +12,6 @@ enum class FeeReason;
bool FeeModeFromString(const std::string& mode_string, FeeEstimateMode& fee_estimate_mode);
std::string StringForFeeReason(FeeReason reason);
+std::string FeeModes(const std::string& delimiter);
#endif // BITCOIN_UTIL_FEES_H
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 541675bcef..6a1048539f 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -817,7 +817,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
create_time = FormatISO8601DateTime(it->second.nCreateTime);
}
if(spk_man.GetCScript(scriptid, script)) {
- file << strprintf("%s %s script=1", HexStr(script.begin(), script.end()), create_time);
+ file << strprintf("%s %s script=1", HexStr(script), create_time);
file << strprintf(" # addr=%s\n", address);
}
}
@@ -1193,7 +1193,7 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
// Check whether we have any work to do
for (const CScript& script : script_pub_keys) {
if (pwallet->IsMine(script) & ISMINE_SPENDABLE) {
- throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script (\"" + HexStr(script.begin(), script.end()) + "\")");
+ throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script (\"" + HexStr(script) + "\")");
}
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 72998c30fd..c05233d0af 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -45,6 +45,8 @@ using interfaces::FoundBlock;
static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
static const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};
+static const uint32_t WALLET_BTC_KB_TO_SAT_B = COIN / 1000; // 1 sat / B = 0.00001 BTC / kB
+
static inline bool GetAvoidReuseFlag(const CWallet* const pwallet, const UniValue& param) {
bool can_avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();
@@ -191,6 +193,42 @@ static std::string LabelFromValue(const UniValue& value)
return label;
}
+/**
+ * Update coin control with fee estimation based on the given parameters
+ *
+ * @param[in] pwallet Wallet pointer
+ * @param[in,out] cc Coin control which is to be updated
+ * @param[in] estimate_mode String value (e.g. "ECONOMICAL")
+ * @param[in] estimate_param Parameter (blocks to confirm, explicit fee rate, etc)
+ * @throws a JSONRPCError if estimate_mode is unknown, or if estimate_param is missing when required
+ */
+static void SetFeeEstimateMode(const CWallet* pwallet, CCoinControl& cc, const UniValue& estimate_mode, const UniValue& estimate_param)
+{
+ if (!estimate_mode.isNull()) {
+ if (!FeeModeFromString(estimate_mode.get_str(), cc.m_fee_mode)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
+ }
+ }
+
+ if (cc.m_fee_mode == FeeEstimateMode::BTC_KB || cc.m_fee_mode == FeeEstimateMode::SAT_B) {
+ if (estimate_param.isNull()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Selected estimate_mode requires a fee rate");
+ }
+
+ CAmount fee_rate = AmountFromValue(estimate_param);
+ if (cc.m_fee_mode == FeeEstimateMode::SAT_B) {
+ fee_rate /= WALLET_BTC_KB_TO_SAT_B;
+ }
+
+ cc.m_feerate = CFeeRate(fee_rate);
+
+ // default RBF to true for explicit fee rate modes
+ if (cc.m_signal_bip125_rbf == boost::none) cc.m_signal_bip125_rbf = true;
+ } else if (!estimate_param.isNull()) {
+ cc.m_confirm_target = ParseConfirmTarget(estimate_param, pwallet->chain().estimateMaxBlocks());
+ }
+}
+
static UniValue getnewaddress(const JSONRPCRequest& request)
{
RPCHelpMan{"getnewaddress",
@@ -369,11 +407,9 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
{"subtractfeefromamount", RPCArg::Type::BOOL, /* default */ "false", "The fee will be deducted from the amount being sent.\n"
" The recipient will receive less bitcoins than you enter in the amount field."},
{"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
- {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"},
- {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
- " \"UNSET\"\n"
- " \"ECONOMICAL\"\n"
- " \"CONSERVATIVE\""},
+ {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"},
+ {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
+ " \"" + FeeModes("\"\n\"") + "\""},
{"avoid_reuse", RPCArg::Type::BOOL, /* default */ "true", "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n"
" dirty if they have previously been used in a transaction."},
},
@@ -384,6 +420,8 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1")
+ HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"donation\" \"seans outpost\"")
+ HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"\" \"\" true")
+ + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"\" \"\" false true 0.00002 " + (CURRENCY_UNIT + "/kB"))
+ + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"\" \"\" false true 2 " + (CURRENCY_ATOM + "/B"))
+ HelpExampleRpc("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\", 0.1, \"donation\", \"seans outpost\"")
},
}.Check(request);
@@ -425,20 +463,12 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
coin_control.m_signal_bip125_rbf = request.params[5].get_bool();
}
- if (!request.params[6].isNull()) {
- coin_control.m_confirm_target = ParseConfirmTarget(request.params[6], pwallet->chain().estimateMaxBlocks());
- }
-
- if (!request.params[7].isNull()) {
- if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
- }
- }
-
coin_control.m_avoid_address_reuse = GetAvoidReuseFlag(pwallet, request.params[8]);
// We also enable partial spend avoidance if reuse avoidance is set.
coin_control.m_avoid_partial_spends |= coin_control.m_avoid_address_reuse;
+ SetFeeEstimateMode(pwallet, coin_control, request.params[7], request.params[6]);
+
EnsureWalletIsUnlocked(pwallet);
CTransactionRef tx = SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, coin_control, std::move(mapValue));
@@ -780,11 +810,9 @@ static UniValue sendmany(const JSONRPCRequest& request)
},
},
{"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
- {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"},
- {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
- " \"UNSET\"\n"
- " \"ECONOMICAL\"\n"
- " \"CONSERVATIVE\""},
+ {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"},
+ {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
+ " \"" + FeeModes("\"\n\"") + "\""},
},
RPCResult{
RPCResult::Type::STR_HEX, "txid", "The transaction id for the send. Only 1 transaction is created regardless of\n"
@@ -830,15 +858,7 @@ static UniValue sendmany(const JSONRPCRequest& request)
coin_control.m_signal_bip125_rbf = request.params[5].get_bool();
}
- if (!request.params[6].isNull()) {
- coin_control.m_confirm_target = ParseConfirmTarget(request.params[6], pwallet->chain().estimateMaxBlocks());
- }
-
- if (!request.params[7].isNull()) {
- if (!FeeModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
- }
- }
+ SetFeeEstimateMode(pwallet, coin_control, request.params[7], request.params[6]);
std::set<CTxDestination> destinations;
std::vector<CRecipient> vecSend;
@@ -964,7 +984,7 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request)
UniValue result(UniValue::VOBJ);
result.pushKV("address", EncodeDestination(dest));
- result.pushKV("redeemScript", HexStr(inner.begin(), inner.end()));
+ result.pushKV("redeemScript", HexStr(inner));
result.pushKV("descriptor", descriptor->ToString());
return result;
}
@@ -2870,7 +2890,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
const CScriptID& hash = CScriptID(boost::get<ScriptHash>(address));
CScript redeemScript;
if (provider->GetCScript(hash, redeemScript)) {
- entry.pushKV("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()));
+ entry.pushKV("redeemScript", HexStr(redeemScript));
// Now check if the redeemScript is actually a P2WSH script
CTxDestination witness_destination;
if (redeemScript.IsPayToWitnessScriptHash()) {
@@ -2882,7 +2902,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
CScript witnessScript;
if (provider->GetCScript(id, witnessScript)) {
- entry.pushKV("witnessScript", HexStr(witnessScript.begin(), witnessScript.end()));
+ entry.pushKV("witnessScript", HexStr(witnessScript));
}
}
}
@@ -2892,13 +2912,13 @@ static UniValue listunspent(const JSONRPCRequest& request)
CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
CScript witnessScript;
if (provider->GetCScript(id, witnessScript)) {
- entry.pushKV("witnessScript", HexStr(witnessScript.begin(), witnessScript.end()));
+ entry.pushKV("witnessScript", HexStr(witnessScript));
}
}
}
}
- entry.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()));
+ entry.pushKV("scriptPubKey", HexStr(scriptPubKey));
entry.pushKV("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue));
entry.pushKV("confirmations", out.nDepth);
entry.pushKV("spendable", out.fSpendable);
@@ -2986,6 +3006,12 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f
if (options.exists("feeRate"))
{
+ if (options.exists("conf_target")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and feeRate");
+ }
+ if (options.exists("estimate_mode")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and feeRate");
+ }
coinControl.m_feerate = CFeeRate(AmountFromValue(options["feeRate"]));
coinControl.fOverrideFeeRate = true;
}
@@ -2996,20 +3022,7 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f
if (options.exists("replaceable")) {
coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool();
}
- if (options.exists("conf_target")) {
- if (options.exists("feeRate")) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and feeRate");
- }
- coinControl.m_confirm_target = ParseConfirmTarget(options["conf_target"], pwallet->chain().estimateMaxBlocks());
- }
- if (options.exists("estimate_mode")) {
- if (options.exists("feeRate")) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and feeRate");
- }
- if (!FeeModeFromString(options["estimate_mode"].get_str(), coinControl.m_fee_mode)) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
- }
- }
+ SetFeeEstimateMode(pwallet, coinControl, options["estimate_mode"], options["conf_target"]);
}
} else {
// if options is null and not a bool
@@ -3077,11 +3090,9 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request)
},
{"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n"
" Allows this transaction to be replaced by a transaction with higher fees"},
- {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"},
- {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
- " \"UNSET\"\n"
- " \"ECONOMICAL\"\n"
- " \"CONSERVATIVE\""},
+ {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks), or fee rate (for " + CURRENCY_UNIT + "/kB or " + CURRENCY_ATOM + "/B estimate modes)"},
+ {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
+ " \"" + FeeModes("\"\n\"") + "\""},
},
"options"},
{"iswitness", RPCArg::Type::BOOL, /* default */ "depends on heuristic tests", "Whether the transaction hex is a serialized witness transaction.\n"
@@ -3249,8 +3260,8 @@ static UniValue bumpfee(const JSONRPCRequest& request)
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid to be bumped"},
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
{
- {"confTarget", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"},
- {"fee_rate", RPCArg::Type::NUM, /* default */ "fall back to 'confTarget'", "fee rate (NOT total fee) to pay, in " + CURRENCY_UNIT + " per kB\n"
+ {"conf_target", RPCArg::Type::NUM, /* default */ "wallet default", "Confirmation target (in blocks)"},
+ {"fee_rate", RPCArg::Type::NUM, /* default */ "fall back to 'conf_target'", "fee rate (NOT total fee) to pay, in " + CURRENCY_UNIT + " per kB\n"
" Specify a fee rate instead of relying on the built-in fee estimator.\n"
"Must be at least 0.0001 " + CURRENCY_UNIT + " per kB higher than the current transaction fee rate.\n"},
{"replaceable", RPCArg::Type::BOOL, /* default */ "true", "Whether the new transaction should still be\n"
@@ -3260,10 +3271,8 @@ static UniValue bumpfee(const JSONRPCRequest& request)
" so the new transaction will not be explicitly bip-125 replaceable (though it may\n"
" still be replaceable in practice, for example if it has unconfirmed ancestors which\n"
" are replaceable)."},
- {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
- " \"UNSET\"\n"
- " \"ECONOMICAL\"\n"
- " \"CONSERVATIVE\""},
+ {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
+ " \"" + FeeModes("\"\n\"") + "\""},
},
"options"},
},
@@ -3302,15 +3311,24 @@ static UniValue bumpfee(const JSONRPCRequest& request)
RPCTypeCheckObj(options,
{
{"confTarget", UniValueType(UniValue::VNUM)},
+ {"conf_target", UniValueType(UniValue::VNUM)},
{"fee_rate", UniValueType(UniValue::VNUM)},
{"replaceable", UniValueType(UniValue::VBOOL)},
{"estimate_mode", UniValueType(UniValue::VSTR)},
},
true, true);
- if (options.exists("confTarget") && options.exists("fee_rate")) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "confTarget can't be set with fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.");
- } else if (options.exists("confTarget")) { // TODO: alias this to conf_target
- coin_control.m_confirm_target = ParseConfirmTarget(options["confTarget"], pwallet->chain().estimateMaxBlocks());
+
+ if (options.exists("confTarget") && options.exists("conf_target")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "confTarget and conf_target options should not both be set. Use conf_target (confTarget is deprecated).");
+ }
+
+ auto conf_target = options.exists("confTarget") ? options["confTarget"] : options["conf_target"];
+
+ if (!conf_target.isNull()) {
+ if (options.exists("fee_rate")) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "conf_target can't be set with fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.");
+ }
+ coin_control.m_confirm_target = ParseConfirmTarget(conf_target, pwallet->chain().estimateMaxBlocks());
} else if (options.exists("fee_rate")) {
CFeeRate fee_rate(AmountFromValue(options["fee_rate"]));
if (fee_rate <= CFeeRate(0)) {
@@ -3322,11 +3340,7 @@ static UniValue bumpfee(const JSONRPCRequest& request)
if (options.exists("replaceable")) {
coin_control.m_signal_bip125_rbf = options["replaceable"].get_bool();
}
- if (options.exists("estimate_mode")) {
- if (!FeeModeFromString(options["estimate_mode"].get_str(), coin_control.m_fee_mode)) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid estimate_mode parameter");
- }
- }
+ SetFeeEstimateMode(pwallet, coin_control, options["estimate_mode"], conf_target);
}
// Make sure the results are valid at least up to the most recent block
@@ -3491,7 +3505,7 @@ public:
std::vector<std::vector<unsigned char>> solutions_data;
txnouttype which_type = Solver(subscript, solutions_data);
obj.pushKV("script", GetTxnOutputType(which_type));
- obj.pushKV("hex", HexStr(subscript.begin(), subscript.end()));
+ obj.pushKV("hex", HexStr(subscript));
CTxDestination embedded;
if (ExtractDestination(subscript, embedded)) {
@@ -3502,7 +3516,7 @@ public:
UniValue wallet_detail = boost::apply_visitor(*this, embedded);
subobj.pushKVs(wallet_detail);
subobj.pushKV("address", EncodeDestination(embedded));
- subobj.pushKV("scriptPubKey", HexStr(subscript.begin(), subscript.end()));
+ subobj.pushKV("scriptPubKey", HexStr(subscript));
// Always report the pubkey at the top level, so that `getnewaddress()['pubkey']` always works.
if (subobj.exists("pubkey")) obj.pushKV("pubkey", subobj["pubkey"]);
obj.pushKV("embedded", std::move(subobj));
@@ -3513,7 +3527,7 @@ public:
UniValue pubkeys(UniValue::VARR);
for (size_t i = 1; i < solutions_data.size() - 1; ++i) {
CPubKey key(solutions_data[i].begin(), solutions_data[i].end());
- pubkeys.push_back(HexStr(key.begin(), key.end()));
+ pubkeys.push_back(HexStr(key));
}
obj.pushKV("pubkeys", std::move(pubkeys));
}
@@ -3669,7 +3683,7 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
ret.pushKV("address", currentAddress);
CScript scriptPubKey = GetScriptForDestination(dest);
- ret.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()));
+ ret.pushKV("scriptPubKey", HexStr(scriptPubKey));
std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
@@ -4016,10 +4030,8 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
{"replaceable", RPCArg::Type::BOOL, /* default */ "wallet default", "Marks this transaction as BIP125 replaceable.\n"
" Allows this transaction to be replaced by a transaction with higher fees"},
{"conf_target", RPCArg::Type::NUM, /* default */ "fall back to wallet's confirmation target (txconfirmtarget)", "Confirmation target (in blocks)"},
- {"estimate_mode", RPCArg::Type::STR, /* default */ "UNSET", "The fee estimate mode, must be one of:\n"
- " \"UNSET\"\n"
- " \"ECONOMICAL\"\n"
- " \"CONSERVATIVE\""},
+ {"estimate_mode", RPCArg::Type::STR, /* default */ "unset", std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
+ " \"" + FeeModes("\"\n\"") + "\""},
},
"options"},
{"bip32derivs", RPCArg::Type::BOOL, /* default */ "true", "Include BIP 32 derivation paths for public keys if we know them"},
diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp
index b4c65a8665..3f85a48ff3 100644
--- a/src/wallet/test/psbt_wallet_tests.cpp
+++ b/src/wallet/test/psbt_wallet_tests.cpp
@@ -63,7 +63,7 @@ BOOST_AUTO_TEST_CASE(psbt_updater_test)
// Get the final tx
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << psbtx;
- std::string final_hex = HexStr(ssTx.begin(), ssTx.end());
+ std::string final_hex = HexStr(ssTx);
BOOST_CHECK_EQUAL(final_hex, "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88701042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000");
// Mutate the transaction so that one of the inputs is invalid
diff --git a/src/wallet/test/wallet_crypto_tests.cpp b/src/wallet/test/wallet_crypto_tests.cpp
index 97f8c94fa6..10ddfa22ef 100644
--- a/src/wallet/test/wallet_crypto_tests.cpp
+++ b/src/wallet/test/wallet_crypto_tests.cpp
@@ -24,10 +24,10 @@ static void TestPassphraseSingle(const std::vector<unsigned char>& vchSalt, cons
if(!correctKey.empty())
BOOST_CHECK_MESSAGE(memcmp(crypt.vchKey.data(), correctKey.data(), crypt.vchKey.size()) == 0, \
- HexStr(crypt.vchKey.begin(), crypt.vchKey.end()) + std::string(" != ") + HexStr(correctKey.begin(), correctKey.end()));
+ HexStr(crypt.vchKey) + std::string(" != ") + HexStr(correctKey));
if(!correctIV.empty())
BOOST_CHECK_MESSAGE(memcmp(crypt.vchIV.data(), correctIV.data(), crypt.vchIV.size()) == 0,
- HexStr(crypt.vchIV.begin(), crypt.vchIV.end()) + std::string(" != ") + HexStr(correctIV.begin(), correctIV.end()));
+ HexStr(crypt.vchIV) + std::string(" != ") + HexStr(correctIV));
}
static void TestPassphrase(const std::vector<unsigned char>& vchSalt, const SecureString& passphrase, uint32_t rounds,