aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml4
-rw-r--r--src/bench/crypto_hash.cpp6
-rw-r--r--src/bench/rollingbloom.cpp3
-rw-r--r--src/fs.cpp85
-rw-r--r--src/fs.h20
-rw-r--r--src/init.cpp2
-rw-r--r--src/interfaces/handler.cpp2
-rw-r--r--src/interfaces/wallet.cpp4
-rw-r--r--src/key_io.cpp2
-rw-r--r--src/netbase.cpp4
-rw-r--r--src/qt/addresstablemodel.cpp2
-rw-r--r--src/qt/rpcconsole.cpp2
-rw-r--r--src/qt/transactiontablemodel.cpp2
-rw-r--r--src/rpc/rawtransaction.cpp18
-rw-r--r--src/rpc/server.cpp5
-rw-r--r--src/script/sign.cpp55
-rw-r--r--src/script/sign.h49
-rw-r--r--src/test/descriptor_tests.cpp2
-rw-r--r--src/test/miner_tests.cpp2
-rw-r--r--src/test/netbase_tests.cpp18
-rw-r--r--src/test/scheduler_tests.cpp2
-rw-r--r--src/test/script_tests.cpp8
-rw-r--r--src/test/util_tests.cpp39
-rw-r--r--src/test/validation_block_tests.cpp2
-rw-r--r--src/txmempool.cpp7
-rw-r--r--src/util.cpp22
-rw-r--r--src/utilstrencodings.cpp53
-rw-r--r--src/utilstrencodings.h47
-rw-r--r--src/wallet/rpcwallet.cpp101
-rw-r--r--src/wallet/test/psbt_wallet_tests.cpp2
-rw-r--r--src/wallet/wallet.cpp26
-rw-r--r--src/wallet/wallet.h2
-rwxr-xr-xtest/functional/combine_logs.py18
-rwxr-xr-xtest/functional/rpc_psbt.py10
-rwxr-xr-xtest/functional/rpc_rawtransaction.py2
-rwxr-xr-xtest/lint/lint-includes.sh2
-rwxr-xr-xtest/lint/lint-locale-dependence.sh2
37 files changed, 435 insertions, 197 deletions
diff --git a/.travis.yml b/.travis.yml
index 7e353ad86f..8819d38914 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -62,7 +62,9 @@ jobs:
RUN_UNIT_TESTS=false
RUN_FUNCTIONAL_TESTS=false
GOAL="install"
- BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports"
+ # -Wno-psabi is to disable ABI warnings: "note: parameter passing for argument of type ... changed in GCC 7.1"
+ # This could be removed once the ABI change warning does not show up by default
+ BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CXXFLAGS=-Wno-psabi"
# Win32
- stage: test
env: >-
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
index bab22f5984..5b0cf27e04 100644
--- a/src/bench/crypto_hash.cpp
+++ b/src/bench/crypto_hash.cpp
@@ -80,18 +80,16 @@ static void SipHash_32b(benchmark::State& state)
static void FastRandom_32bit(benchmark::State& state)
{
FastRandomContext rng(true);
- uint32_t x = 0;
while (state.KeepRunning()) {
- x += rng.rand32();
+ rng.rand32();
}
}
static void FastRandom_1bit(benchmark::State& state)
{
FastRandomContext rng(true);
- uint32_t x = 0;
while (state.KeepRunning()) {
- x += rng.randbool();
+ rng.randbool();
}
}
diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp
index 43e7635047..0a99ea3184 100644
--- a/src/bench/rollingbloom.cpp
+++ b/src/bench/rollingbloom.cpp
@@ -12,7 +12,6 @@ static void RollingBloom(benchmark::State& state)
CRollingBloomFilter filter(120000, 0.000001);
std::vector<unsigned char> data(32);
uint32_t count = 0;
- uint64_t match = 0;
while (state.KeepRunning()) {
count++;
data[0] = count;
@@ -25,7 +24,7 @@ static void RollingBloom(benchmark::State& state)
data[1] = count >> 16;
data[2] = count >> 8;
data[3] = count;
- match += filter.contains(data);
+ filter.contains(data);
}
}
diff --git a/src/fs.cpp b/src/fs.cpp
index 570ed3e2ee..e7d06e45ab 100644
--- a/src/fs.cpp
+++ b/src/fs.cpp
@@ -1,5 +1,12 @@
#include <fs.h>
+#ifndef WIN32
+#include <fcntl.h>
+#else
+#include <codecvt>
+#include <windows.h>
+#endif
+
namespace fsbridge {
FILE *fopen(const fs::path& p, const char *mode)
@@ -12,4 +19,82 @@ FILE *freopen(const fs::path& p, const char *mode, FILE *stream)
return ::freopen(p.string().c_str(), mode, stream);
}
+#ifndef WIN32
+
+static std::string GetErrorReason() {
+ return std::strerror(errno);
+}
+
+FileLock::FileLock(const fs::path& file)
+{
+ fd = open(file.string().c_str(), O_RDWR);
+ if (fd == -1) {
+ reason = GetErrorReason();
+ }
+}
+
+FileLock::~FileLock()
+{
+ if (fd != -1) {
+ close(fd);
+ }
+}
+
+bool FileLock::TryLock()
+{
+ if (fd == -1) {
+ return false;
+ }
+ struct flock lock;
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ if (fcntl(fd, F_SETLK, &lock) == -1) {
+ reason = GetErrorReason();
+ return false;
+ }
+ return true;
+}
+#else
+
+static std::string GetErrorReason() {
+ wchar_t* err;
+ FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<WCHAR*>(&err), 0, nullptr);
+ std::wstring err_str(err);
+ LocalFree(err);
+ return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().to_bytes(err_str);
+}
+
+FileLock::FileLock(const fs::path& file)
+{
+ hFile = CreateFileW(file.wstring().c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
+ if (hFile == INVALID_HANDLE_VALUE) {
+ reason = GetErrorReason();
+ }
+}
+
+FileLock::~FileLock()
+{
+ if (hFile != INVALID_HANDLE_VALUE) {
+ CloseHandle(hFile);
+ }
+}
+
+bool FileLock::TryLock()
+{
+ if (hFile == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+ _OVERLAPPED overlapped = {0};
+ if (!LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, 0, 0, &overlapped)) {
+ reason = GetErrorReason();
+ return false;
+ }
+ return true;
+}
+#endif
+
} // fsbridge
diff --git a/src/fs.h b/src/fs.h
index abb4be254b..e3ff51604d 100644
--- a/src/fs.h
+++ b/src/fs.h
@@ -19,6 +19,26 @@ namespace fs = boost::filesystem;
namespace fsbridge {
FILE *fopen(const fs::path& p, const char *mode);
FILE *freopen(const fs::path& p, const char *mode, FILE *stream);
+
+ class FileLock
+ {
+ public:
+ FileLock() = delete;
+ FileLock(const FileLock&) = delete;
+ FileLock(FileLock&&) = delete;
+ explicit FileLock(const fs::path& file);
+ ~FileLock();
+ bool TryLock();
+ std::string GetReason() { return reason; }
+
+ private:
+ std::string reason;
+#ifndef WIN32
+ int fd = -1;
+#else
+ void* hFile = (void*)-1; // INVALID_HANDLE_VALUE
+#endif
+ };
};
#endif // BITCOIN_FS_H
diff --git a/src/init.cpp b/src/init.cpp
index 2131a6adc0..bd330459f6 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -51,13 +51,13 @@
#ifndef WIN32
#include <signal.h>
+#include <sys/stat.h>
#endif
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/bind.hpp>
-#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/thread.hpp>
#include <openssl/crypto.h>
diff --git a/src/interfaces/handler.cpp b/src/interfaces/handler.cpp
index 80f461f4d3..ddf9b342d8 100644
--- a/src/interfaces/handler.cpp
+++ b/src/interfaces/handler.cpp
@@ -15,7 +15,7 @@ namespace {
class HandlerImpl : public Handler
{
public:
- HandlerImpl(boost::signals2::connection connection) : m_connection(std::move(connection)) {}
+ explicit HandlerImpl(boost::signals2::connection connection) : m_connection(std::move(connection)) {}
void disconnect() override { m_connection.disconnect(); }
diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp
index 703c0811ac..01467f3a1c 100644
--- a/src/interfaces/wallet.cpp
+++ b/src/interfaces/wallet.cpp
@@ -31,7 +31,7 @@ namespace {
class PendingWalletTxImpl : public PendingWalletTx
{
public:
- PendingWalletTxImpl(CWallet& wallet) : m_wallet(wallet), m_key(&wallet) {}
+ explicit PendingWalletTxImpl(CWallet& wallet) : m_wallet(wallet), m_key(&wallet) {}
const CTransaction& get() override { return *m_tx; }
@@ -117,7 +117,7 @@ static WalletTxOut MakeWalletTxOut(CWallet& wallet, const CWalletTx& wtx, int n,
class WalletImpl : public Wallet
{
public:
- WalletImpl(const std::shared_ptr<CWallet>& wallet) : m_shared_wallet(wallet), m_wallet(*wallet.get()) {}
+ explicit WalletImpl(const std::shared_ptr<CWallet>& wallet) : m_shared_wallet(wallet), m_wallet(*wallet.get()) {}
bool encryptWallet(const SecureString& wallet_passphrase) override
{
diff --git a/src/key_io.cpp b/src/key_io.cpp
index 5c5e2dc031..c6a541cdb1 100644
--- a/src/key_io.cpp
+++ b/src/key_io.cpp
@@ -24,7 +24,7 @@ private:
const CChainParams& m_params;
public:
- DestinationEncoder(const CChainParams& params) : m_params(params) {}
+ explicit DestinationEncoder(const CChainParams& params) : m_params(params) {}
std::string operator()(const CKeyID& id) const
{
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 9750173987..4b63757f3d 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -19,8 +19,6 @@
#include <fcntl.h>
#endif
-#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
-
#if !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
@@ -37,7 +35,7 @@ static const int SOCKS5_RECV_TIMEOUT = 20 * 1000;
static std::atomic<bool> interruptSocks5Recv(false);
enum Network ParseNetwork(std::string net) {
- boost::to_lower(net);
+ Downcase(net);
if (net == "ipv4") return NET_IPV4;
if (net == "ipv6") return NET_IPV6;
if (net == "onion") return NET_ONION;
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 380a3ddb84..2f88e15d21 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -71,7 +71,7 @@ public:
QList<AddressTableEntry> cachedAddressTable;
AddressTableModel *parent;
- AddressTablePriv(AddressTableModel *_parent):
+ explicit AddressTablePriv(AddressTableModel *_parent):
parent(_parent) {}
void refreshAddressTable(interfaces::Wallet& wallet)
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 66e36f0b67..00fc73574e 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -82,7 +82,7 @@ class RPCExecutor : public QObject
{
Q_OBJECT
public:
- RPCExecutor(interfaces::Node& node) : m_node(node) {}
+ explicit RPCExecutor(interfaces::Node& node) : m_node(node) {}
public Q_SLOTS:
void request(const QString &command, const QString &walletID);
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 4fa941b630..b4be068904 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -60,7 +60,7 @@ struct TxLessThan
class TransactionTablePriv
{
public:
- TransactionTablePriv(TransactionTableModel *_parent) :
+ explicit TransactionTablePriv(TransactionTableModel *_parent) :
parent(_parent)
{
}
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index 7ca097f8cf..248b963c0b 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -1458,11 +1458,8 @@ UniValue decodepsbt(const JSONRPCRequest& request)
UniValue keypath(UniValue::VOBJ);
keypath.pushKV("pubkey", HexStr(entry.first));
- uint32_t fingerprint = entry.second.at(0);
- keypath.pushKV("master_fingerprint", strprintf("%08x", bswap_32(fingerprint)));
-
- entry.second.erase(entry.second.begin());
- keypath.pushKV("path", WriteHDKeypath(entry.second));
+ keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint)));
+ keypath.pushKV("path", WriteHDKeypath(entry.second.path));
keypaths.push_back(keypath);
}
in.pushKV("bip32_derivs", keypaths);
@@ -1520,12 +1517,8 @@ UniValue decodepsbt(const JSONRPCRequest& request)
for (auto entry : output.hd_keypaths) {
UniValue keypath(UniValue::VOBJ);
keypath.pushKV("pubkey", HexStr(entry.first));
-
- uint32_t fingerprint = entry.second.at(0);
- keypath.pushKV("master_fingerprint", strprintf("%08x", bswap_32(fingerprint)));
-
- entry.second.erase(entry.second.begin());
- keypath.pushKV("path", WriteHDKeypath(entry.second));
+ keypath.pushKV("master_fingerprint", strprintf("%08x", ReadBE32(entry.second.fingerprint)));
+ keypath.pushKV("path", WriteHDKeypath(entry.second.path));
keypaths.push_back(keypath);
}
out.pushKV("bip32_derivs", keypaths);
@@ -1646,8 +1639,7 @@ UniValue finalizepsbt(const JSONRPCRequest& request)
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
PSBTInput& input = psbtx.inputs.at(i);
- SignatureData sigdata;
- complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, *psbtx.tx, input, sigdata, i, 1);
+ complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, *psbtx.tx, input, i, 1);
}
UniValue result(UniValue::VOBJ);
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp
index e46bf2f765..7d7e83fea8 100644
--- a/src/rpc/server.cpp
+++ b/src/rpc/server.cpp
@@ -16,7 +16,6 @@
#include <boost/bind.hpp>
#include <boost/signals2/signal.hpp>
-#include <boost/algorithm/string/case_conv.hpp> // for to_upper()
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
@@ -192,9 +191,7 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
if (!category.empty())
strRet += "\n";
category = pcmd->category;
- std::string firstLetter = category.substr(0,1);
- boost::to_upper(firstLetter);
- strRet += "== " + firstLetter + category.substr(1) + " ==\n";
+ strRet += "== " + Capitalize(category) + " ==\n";
}
}
strRet += strHelp + "\n";
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index 23af1bd97f..d779910425 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -50,10 +50,6 @@ static bool GetCScript(const SigningProvider& provider, const SignatureData& sig
static bool GetPubKey(const SigningProvider& provider, SignatureData& sigdata, const CKeyID& address, CPubKey& pubkey)
{
- if (provider.GetPubKey(address, pubkey)) {
- sigdata.misc_pubkeys.emplace(pubkey.GetID(), pubkey);
- return true;
- }
// Look for pubkey in all partial sigs
const auto it = sigdata.signatures.find(address);
if (it != sigdata.signatures.end()) {
@@ -63,7 +59,15 @@ static bool GetPubKey(const SigningProvider& provider, SignatureData& sigdata, c
// Look for pubkey in pubkey list
const auto& pk_it = sigdata.misc_pubkeys.find(address);
if (pk_it != sigdata.misc_pubkeys.end()) {
- pubkey = pk_it->second;
+ pubkey = pk_it->second.first;
+ return true;
+ }
+ // Query the underlying provider
+ if (provider.GetPubKey(address, pubkey)) {
+ KeyOriginInfo info;
+ if (provider.GetKeyOrigin(address, info)) {
+ sigdata.misc_pubkeys.emplace(address, std::make_pair(pubkey, std::move(info)));
+ }
return true;
}
return false;
@@ -232,7 +236,7 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
return sigdata.complete;
}
-bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, SignatureData& sigdata, int index, int sighash)
+bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, int index, int sighash)
{
// if this input has a final scriptsig or scriptwitness, don't do anything with it
if (!input.final_script_sig.empty() || !input.final_script_witness.IsNull()) {
@@ -240,6 +244,7 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t
}
// Fill SignatureData with input info
+ SignatureData sigdata;
input.FillSignatureData(sigdata);
// Get UTXO
@@ -271,6 +276,16 @@ bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& t
// Verify that a witness signature was produced in case one was required.
if (require_witness_sig && !sigdata.witness) return false;
input.FromSignatureData(sigdata);
+
+ // If both UTXO types are present, drop the unnecessary one.
+ if (input.non_witness_utxo && !input.witness_utxo.IsNull()) {
+ if (sigdata.witness) {
+ input.non_witness_utxo = nullptr;
+ } else {
+ input.witness_utxo.SetNull();
+ }
+ }
+
return sig_complete;
}
@@ -541,7 +556,7 @@ void PSBTInput::FillSignatureData(SignatureData& sigdata) const
sigdata.witness_script = witness_script;
}
for (const auto& key_pair : hd_keypaths) {
- sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair.first);
+ sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair);
}
}
@@ -569,6 +584,9 @@ void PSBTInput::FromSignatureData(const SignatureData& sigdata)
if (witness_script.empty() && !sigdata.witness_script.empty()) {
witness_script = sigdata.witness_script;
}
+ for (const auto& entry : sigdata.misc_pubkeys) {
+ hd_keypaths.emplace(entry.second);
+ }
}
void PSBTInput::Merge(const PSBTInput& input)
@@ -610,7 +628,7 @@ void PSBTOutput::FillSignatureData(SignatureData& sigdata) const
sigdata.witness_script = witness_script;
}
for (const auto& key_pair : hd_keypaths) {
- sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair.first);
+ sigdata.misc_pubkeys.emplace(key_pair.first.GetID(), key_pair);
}
}
@@ -622,6 +640,9 @@ void PSBTOutput::FromSignatureData(const SignatureData& sigdata)
if (witness_script.empty() && !sigdata.witness_script.empty()) {
witness_script = sigdata.witness_script;
}
+ for (const auto& entry : sigdata.misc_pubkeys) {
+ hd_keypaths.emplace(entry.second);
+ }
}
bool PSBTOutput::IsNull() const
@@ -638,14 +659,26 @@ void PSBTOutput::Merge(const PSBTOutput& output)
if (witness_script.empty() && !output.witness_script.empty()) witness_script = output.witness_script;
}
-bool PublicOnlySigningProvider::GetCScript(const CScriptID &scriptid, CScript& script) const
+bool HidingSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const
{
return m_provider->GetCScript(scriptid, script);
}
-bool PublicOnlySigningProvider::GetPubKey(const CKeyID &address, CPubKey& pubkey) const
+bool HidingSigningProvider::GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const
+{
+ return m_provider->GetPubKey(keyid, pubkey);
+}
+
+bool HidingSigningProvider::GetKey(const CKeyID& keyid, CKey& key) const
+{
+ if (m_hide_secret) return false;
+ return m_provider->GetKey(keyid, key);
+}
+
+bool HidingSigningProvider::GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const
{
- return m_provider->GetPubKey(address, pubkey);
+ if (m_hide_origin) return false;
+ return m_provider->GetKeyOrigin(keyid, info);
}
bool FlatSigningProvider::GetCScript(const CScriptID& scriptid, CScript& script) const { return LookupHelper(scripts, scriptid, script); }
diff --git a/src/script/sign.h b/src/script/sign.h
index 7ade715ee2..18b7320998 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -20,6 +20,12 @@ class CTransaction;
struct CMutableTransaction;
+struct KeyOriginInfo
+{
+ unsigned char fingerprint[4];
+ std::vector<uint32_t> path;
+};
+
/** An interface to be implemented by keystores that support signing. */
class SigningProvider
{
@@ -28,19 +34,24 @@ public:
virtual bool GetCScript(const CScriptID &scriptid, CScript& script) const { return false; }
virtual bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const { return false; }
virtual bool GetKey(const CKeyID &address, CKey& key) const { return false; }
+ virtual bool GetKeyOrigin(const CKeyID& id, KeyOriginInfo& info) const { return false; }
};
extern const SigningProvider& DUMMY_SIGNING_PROVIDER;
-class PublicOnlySigningProvider : public SigningProvider
+class HidingSigningProvider : public SigningProvider
{
private:
+ const bool m_hide_secret;
+ const bool m_hide_origin;
const SigningProvider* m_provider;
public:
- PublicOnlySigningProvider(const SigningProvider* provider) : m_provider(provider) {}
- bool GetCScript(const CScriptID &scriptid, CScript& script) const;
- bool GetPubKey(const CKeyID &address, CPubKey& pubkey) const;
+ HidingSigningProvider(const SigningProvider* provider, bool hide_secret, bool hide_origin) : m_hide_secret(hide_secret), m_hide_origin(hide_origin), m_provider(provider) {}
+ bool GetCScript(const CScriptID& scriptid, CScript& script) const override;
+ bool GetPubKey(const CKeyID& keyid, CPubKey& pubkey) const override;
+ bool GetKey(const CKeyID& keyid, CKey& key) const override;
+ bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
};
struct FlatSigningProvider final : public SigningProvider
@@ -98,7 +109,7 @@ struct SignatureData {
CScript witness_script; ///< The witnessScript (if any) for the input. witnessScripts are used in P2WSH outputs.
CScriptWitness scriptWitness; ///< The scriptWitness of an input. Contains complete signatures or the traditional partial signatures format. scriptWitness is part of a transaction input per BIP 144.
std::map<CKeyID, SigPair> signatures; ///< BIP 174 style partial signatures for the input. May contain all signatures necessary for producing a final scriptSig or scriptWitness.
- std::map<CKeyID, CPubKey> misc_pubkeys;
+ std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> misc_pubkeys;
SignatureData() {}
explicit SignatureData(const CScript& script) : scriptSig(script) {}
@@ -155,7 +166,7 @@ void UnserializeFromVector(Stream& s, X&... args)
// Deserialize HD keypaths into a map
template<typename Stream>
-void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths)
+void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std::map<CPubKey, KeyOriginInfo>& hd_keypaths)
{
// Make sure that the key is the size of pubkey + 1
if (key.size() != CPubKey::PUBLIC_KEY_SIZE + 1 && key.size() != CPubKey::COMPRESSED_PUBLIC_KEY_SIZE + 1) {
@@ -172,25 +183,31 @@ void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std
// Read in key path
uint64_t value_len = ReadCompactSize(s);
- std::vector<uint32_t> keypath;
- for (unsigned int i = 0; i < value_len; i += sizeof(uint32_t)) {
+ if (value_len % 4 || value_len == 0) {
+ throw std::ios_base::failure("Invalid length for HD key path");
+ }
+
+ KeyOriginInfo keypath;
+ s >> keypath.fingerprint;
+ for (unsigned int i = 4; i < value_len; i += sizeof(uint32_t)) {
uint32_t index;
s >> index;
- keypath.push_back(index);
+ keypath.path.push_back(index);
}
// Add to map
- hd_keypaths.emplace(pubkey, keypath);
+ hd_keypaths.emplace(pubkey, std::move(keypath));
}
// Serialize HD keypaths to a stream from a map
template<typename Stream>
-void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths, uint8_t type)
+void SerializeHDKeypaths(Stream& s, const std::map<CPubKey, KeyOriginInfo>& hd_keypaths, uint8_t type)
{
for (auto keypath_pair : hd_keypaths) {
SerializeToVector(s, type, MakeSpan(keypath_pair.first));
- WriteCompactSize(s, keypath_pair.second.size() * sizeof(uint32_t));
- for (auto& path : keypath_pair.second) {
+ WriteCompactSize(s, (keypath_pair.second.path.size() + 1) * sizeof(uint32_t));
+ s << keypath_pair.second.fingerprint;
+ for (const auto& path : keypath_pair.second.path) {
s << path;
}
}
@@ -205,7 +222,7 @@ struct PSBTInput
CScript witness_script;
CScript final_script_sig;
CScriptWitness final_script_witness;
- std::map<CPubKey, std::vector<uint32_t>> hd_keypaths;
+ std::map<CPubKey, KeyOriginInfo> hd_keypaths;
std::map<CKeyID, SigPair> partial_sigs;
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
int sighash_type = 0;
@@ -418,7 +435,7 @@ struct PSBTOutput
{
CScript redeem_script;
CScript witness_script;
- std::map<CPubKey, std::vector<uint32_t>> hd_keypaths;
+ std::map<CPubKey, KeyOriginInfo> hd_keypaths;
std::map<std::vector<unsigned char>, std::vector<unsigned char>> unknown;
bool IsNull() const;
@@ -687,7 +704,7 @@ bool SignSignature(const SigningProvider &provider, const CScript& fromPubKey, C
bool SignSignature(const SigningProvider &provider, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType);
/** Signs a PSBTInput, verifying that all provided data matches what is being signed. */
-bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, SignatureData& sigdata, int index, int sighash = 1);
+bool SignPSBTInput(const SigningProvider& provider, const CMutableTransaction& tx, PSBTInput& input, int index, int sighash = SIGHASH_ALL);
/** Extract signature data from a transaction input, and insert it. */
SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nIn, const CTxOut& txout);
diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp
index f189222be8..e739b84a48 100644
--- a/src/test/descriptor_tests.cpp
+++ b/src/test/descriptor_tests.cpp
@@ -64,7 +64,7 @@ void Check(const std::string& prv, const std::string& pub, int flags, const std:
BOOST_CHECK_EQUAL(pub, pub2);
// Check that both can be serialized with private key back to the private version, but not without private key.
- std::string prv1, prv2;
+ std::string prv1;
BOOST_CHECK(parse_priv->ToPrivateString(keys_priv, prv1));
BOOST_CHECK_EQUAL(prv, prv1);
BOOST_CHECK(!parse_priv->ToPrivateString(keys_pub, prv1));
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index 2b9641b6d4..c4793472d4 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -29,7 +29,7 @@ BOOST_FIXTURE_TEST_SUITE(miner_tests, TestingSetup)
// BOOST_CHECK_EXCEPTION predicates to check the specific validation error
class HasReason {
public:
- HasReason(const std::string& reason) : m_reason(reason) {}
+ explicit HasReason(const std::string& reason) : m_reason(reason) {}
bool operator() (const std::runtime_error& e) const {
return std::string(e.what()).find(m_reason) != std::string::npos;
};
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index 9c1af6bdf6..8072eb922d 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -302,4 +302,22 @@ BOOST_AUTO_TEST_CASE(netbase_getgroup)
BOOST_CHECK(CreateInternal("baz.net").GetGroup() == internal_group);
}
+BOOST_AUTO_TEST_CASE(netbase_parsenetwork)
+{
+ BOOST_CHECK_EQUAL(ParseNetwork("ipv4"), NET_IPV4);
+ BOOST_CHECK_EQUAL(ParseNetwork("ipv6"), NET_IPV6);
+ BOOST_CHECK_EQUAL(ParseNetwork("onion"), NET_ONION);
+ BOOST_CHECK_EQUAL(ParseNetwork("tor"), NET_ONION);
+
+ BOOST_CHECK_EQUAL(ParseNetwork("IPv4"), NET_IPV4);
+ BOOST_CHECK_EQUAL(ParseNetwork("IPv6"), NET_IPV6);
+ BOOST_CHECK_EQUAL(ParseNetwork("ONION"), NET_ONION);
+ BOOST_CHECK_EQUAL(ParseNetwork("TOR"), NET_ONION);
+
+ BOOST_CHECK_EQUAL(ParseNetwork(":)"), NET_UNROUTABLE);
+ BOOST_CHECK_EQUAL(ParseNetwork("tÖr"), NET_UNROUTABLE);
+ BOOST_CHECK_EQUAL(ParseNetwork("\xfe\xff"), NET_UNROUTABLE);
+ BOOST_CHECK_EQUAL(ParseNetwork(""), NET_UNROUTABLE);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
index 2af0ab22da..814459c2bc 100644
--- a/src/test/scheduler_tests.cpp
+++ b/src/test/scheduler_tests.cpp
@@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE(manythreads)
boost::mutex counterMutex[10];
int counter[10] = { 0 };
- FastRandomContext rng(42);
+ FastRandomContext rng{/* fDeterministic */ true};
auto zeroToNine = [](FastRandomContext& rc) -> int { return rc.randrange(10); }; // [0, 9]
auto randomMsec = [](FastRandomContext& rc) -> int { return -11 + (int)rc.randrange(1012); }; // [-11, 1000]
auto randomDelta = [](FastRandomContext& rc) -> int { return -1000 + (int)rc.randrange(2001); }; // [-1000, 1000]
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index bc671394c0..67c377778f 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -937,17 +937,19 @@ BOOST_AUTO_TEST_CASE(script_build)
}
}
+#ifdef UPDATE_JSON_TESTS
std::string strGen;
-
+#endif
for (TestBuilder& test : tests) {
test.Test();
std::string str = JSONPrettyPrint(test.GetJSON());
-#ifndef UPDATE_JSON_TESTS
+#ifdef UPDATE_JSON_TESTS
+ strGen += str + ",\n";
+#else
if (tests_set.count(str) == 0) {
BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment());
}
#endif
- strGen += str + ",\n";
}
#ifdef UPDATE_JSON_TESTS
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index b2960446eb..8e2f5abe66 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -1217,4 +1217,43 @@ BOOST_AUTO_TEST_CASE(test_DirIsWritable)
fs::remove(tmpdirname);
}
+BOOST_AUTO_TEST_CASE(test_ToLower)
+{
+ BOOST_CHECK_EQUAL(ToLower('@'), '@');
+ BOOST_CHECK_EQUAL(ToLower('A'), 'a');
+ BOOST_CHECK_EQUAL(ToLower('Z'), 'z');
+ BOOST_CHECK_EQUAL(ToLower('['), '[');
+ BOOST_CHECK_EQUAL(ToLower(0), 0);
+ BOOST_CHECK_EQUAL(ToLower(255), 255);
+
+ std::string testVector;
+ Downcase(testVector);
+ BOOST_CHECK_EQUAL(testVector, "");
+
+ testVector = "#HODL";
+ Downcase(testVector);
+ BOOST_CHECK_EQUAL(testVector, "#hodl");
+
+ testVector = "\x00\xfe\xff";
+ Downcase(testVector);
+ BOOST_CHECK_EQUAL(testVector, "\x00\xfe\xff");
+}
+
+BOOST_AUTO_TEST_CASE(test_ToUpper)
+{
+ BOOST_CHECK_EQUAL(ToUpper('`'), '`');
+ BOOST_CHECK_EQUAL(ToUpper('a'), 'A');
+ BOOST_CHECK_EQUAL(ToUpper('z'), 'Z');
+ BOOST_CHECK_EQUAL(ToUpper('{'), '{');
+ BOOST_CHECK_EQUAL(ToUpper(0), 0);
+ BOOST_CHECK_EQUAL(ToUpper(255), 255);
+}
+
+BOOST_AUTO_TEST_CASE(test_Capitalize)
+{
+ BOOST_CHECK_EQUAL(Capitalize(""), "");
+ BOOST_CHECK_EQUAL(Capitalize("bitcoin"), "Bitcoin");
+ BOOST_CHECK_EQUAL(Capitalize("\x00\xfe\xff"), "\x00\xfe\xff");
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index 37c4f79133..4316f37999 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -23,7 +23,7 @@ BOOST_FIXTURE_TEST_SUITE(validation_block_tests, RegtestingSetup)
struct TestSubscriber : public CValidationInterface {
uint256 m_expected_tip;
- TestSubscriber(uint256 tip) : m_expected_tip(tip) {}
+ explicit TestSubscriber(uint256 tip) : m_expected_tip(tip) {}
void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) override
{
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index 8bada4dce8..c7ff7b5477 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -640,8 +640,6 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
innerUsage += memusage::DynamicUsage(links.parents) + memusage::DynamicUsage(links.children);
bool fDependsWait = false;
setEntries setParentCheck;
- int64_t parentSizes = 0;
- int64_t parentSigOpCost = 0;
for (const CTxIn &txin : tx.vin) {
// Check that every mempool transaction's inputs refer to available coins, or other mempool tx's.
indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash);
@@ -649,10 +647,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
const CTransaction& tx2 = it2->GetTx();
assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull());
fDependsWait = true;
- if (setParentCheck.insert(it2).second) {
- parentSizes += it2->GetTxSize();
- parentSigOpCost += it2->GetSigOpCost();
- }
+ setParentCheck.insert(it2);
} else {
assert(pcoins->HaveCoin(txin.prevout));
}
diff --git a/src/util.cpp b/src/util.cpp
index 1aab85264f..55b09dcff8 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -71,7 +71,6 @@
#include <malloc.h>
#endif
-#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/thread.hpp>
#include <openssl/crypto.h>
#include <openssl/rand.h>
@@ -139,7 +138,7 @@ instance_of_cinit;
* cleans them up and thus automatically unlocks them, or ReleaseDirectoryLocks
* is called.
*/
-static std::map<std::string, std::unique_ptr<boost::interprocess::file_lock>> dir_locks;
+static std::map<std::string, std::unique_ptr<fsbridge::FileLock>> dir_locks;
/** Mutex to protect dir_locks. */
static std::mutex cs_dir_locks;
@@ -156,18 +155,13 @@ bool LockDirectory(const fs::path& directory, const std::string lockfile_name, b
// Create empty lock file if it doesn't exist.
FILE* file = fsbridge::fopen(pathLockFile, "a");
if (file) fclose(file);
-
- try {
- auto lock = MakeUnique<boost::interprocess::file_lock>(pathLockFile.string().c_str());
- if (!lock->try_lock()) {
- return false;
- }
- if (!probe_only) {
- // Lock successful and we're not just probing, put it into the map
- dir_locks.emplace(pathLockFile.string(), std::move(lock));
- }
- } catch (const boost::interprocess::interprocess_exception& e) {
- return error("Error while attempting to lock directory %s: %s", directory.string(), e.what());
+ auto lock = MakeUnique<fsbridge::FileLock>(pathLockFile);
+ if (!lock->TryLock()) {
+ return error("Error while attempting to lock directory %s: %s", directory.string(), lock->GetReason());
+ }
+ if (!probe_only) {
+ // Lock successful and we're not just probing, put it into the map
+ dir_locks.emplace(pathLockFile.string(), std::move(lock));
}
return true;
}
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp
index a06d88cb19..2326383586 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -7,6 +7,7 @@
#include <tinyformat.h>
+#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <errno.h>
@@ -544,3 +545,55 @@ bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out)
return true;
}
+bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath)
+{
+ std::stringstream ss(keypath_str);
+ std::string item;
+ bool first = true;
+ while (std::getline(ss, item, '/')) {
+ if (item.compare("m") == 0) {
+ if (first) {
+ first = false;
+ continue;
+ }
+ return false;
+ }
+ // Finds whether it is hardened
+ uint32_t path = 0;
+ size_t pos = item.find("'");
+ if (pos != std::string::npos) {
+ // The hardened tick can only be in the last index of the string
+ if (pos != item.size() - 1) {
+ return false;
+ }
+ path |= 0x80000000;
+ item = item.substr(0, item.size() - 1); // Drop the last character which is the hardened tick
+ }
+
+ // Ensure this is only numbers
+ if (item.find_first_not_of( "0123456789" ) != std::string::npos) {
+ return false;
+ }
+ uint32_t number;
+ if (!ParseUInt32(item, &number)) {
+ return false;
+ }
+ path |= number;
+
+ keypath.push_back(path);
+ first = false;
+ }
+ return true;
+}
+
+void Downcase(std::string& str)
+{
+ std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c){return ToLower(c);});
+}
+
+std::string Capitalize(std::string str)
+{
+ if (str.empty()) return str;
+ str[0] = ToUpper(str.front());
+ return str;
+}
diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h
index 5f2211b5dc..846a3917a2 100644
--- a/src/utilstrencodings.h
+++ b/src/utilstrencodings.h
@@ -183,4 +183,51 @@ bool ConvertBits(const O& outfn, I it, I end) {
return true;
}
+/** Parse an HD keypaths like "m/7/0'/2000". */
+bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath);
+
+/**
+ * Converts the given character to its lowercase equivalent.
+ * This function is locale independent. It only converts uppercase
+ * characters in the standard 7-bit ASCII range.
+ * @param[in] c the character to convert to lowercase.
+ * @return the lowercase equivalent of c; or the argument
+ * if no conversion is possible.
+ */
+constexpr unsigned char ToLower(unsigned char c)
+{
+ return (c >= 'A' && c <= 'Z' ? (c - 'A') + 'a' : c);
+}
+
+/**
+ * Converts the given string to its lowercase equivalent.
+ * This function is locale independent. It only converts uppercase
+ * characters in the standard 7-bit ASCII range.
+ * @param[in,out] str the string to convert to lowercase.
+ */
+void Downcase(std::string& str);
+
+/**
+ * Converts the given character to its uppercase equivalent.
+ * This function is locale independent. It only converts lowercase
+ * characters in the standard 7-bit ASCII range.
+ * @param[in] c the character to convert to uppercase.
+ * @return the uppercase equivalent of c; or the argument
+ * if no conversion is possible.
+ */
+constexpr unsigned char ToUpper(unsigned char c)
+{
+ return (c >= 'a' && c <= 'z' ? (c - 'a') + 'A' : c);
+}
+
+/**
+ * Capitalizes the first character of the given string.
+ * This function is locale independent. It only capitalizes the
+ * first character of the argument if it has an uppercase equivalent
+ * in the standard 7-bit ASCII range.
+ * @param[in] str the string to capitalize.
+ * @return string with the first letter capitalized.
+ */
+std::string Capitalize(std::string str);
+
#endif // BITCOIN_UTILSTRENCODINGS_H
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index c82c914e1e..8d9b67d82f 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -3842,74 +3842,17 @@ UniValue sethdseed(const JSONRPCRequest& request)
return NullUniValue;
}
-bool ParseHDKeypath(std::string keypath_str, std::vector<uint32_t>& keypath)
-{
- std::stringstream ss(keypath_str);
- std::string item;
- bool first = true;
- while (std::getline(ss, item, '/')) {
- if (item.compare("m") == 0) {
- if (first) {
- first = false;
- continue;
- }
- return false;
- }
- // Finds whether it is hardened
- uint32_t path = 0;
- size_t pos = item.find("'");
- if (pos != std::string::npos) {
- // The hardened tick can only be in the last index of the string
- if (pos != item.size() - 1) {
- return false;
- }
- path |= 0x80000000;
- item = item.substr(0, item.size() - 1); // Drop the last character which is the hardened tick
- }
-
- // Ensure this is only numbers
- if (item.find_first_not_of( "0123456789" ) != std::string::npos) {
- return false;
- }
- uint32_t number;
- if (!ParseUInt32(item, &number)) {
- return false;
- }
- path |= number;
-
- keypath.push_back(path);
- first = false;
- }
- return true;
-}
-
-void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubKey, std::vector<uint32_t>>& hd_keypaths)
+void AddKeypathToMap(const CWallet* pwallet, const CKeyID& keyID, std::map<CPubKey, KeyOriginInfo>& hd_keypaths)
{
CPubKey vchPubKey;
if (!pwallet->GetPubKey(keyID, vchPubKey)) {
return;
}
- CKeyMetadata meta;
- auto it = pwallet->mapKeyMetadata.find(keyID);
- if (it != pwallet->mapKeyMetadata.end()) {
- meta = it->second;
+ KeyOriginInfo info;
+ if (!pwallet->GetKeyOrigin(keyID, info)) {
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken");
}
- std::vector<uint32_t> keypath;
- if (!meta.hdKeypath.empty()) {
- if (!ParseHDKeypath(meta.hdKeypath, keypath)) {
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Internal keypath is broken");
- }
- // Get the proper master key id
- CKey key;
- pwallet->GetKey(meta.hd_seed_id, key);
- CExtKey masterKey;
- masterKey.SetSeed(key.begin(), key.size());
- // Add to map
- keypath.insert(keypath.begin(), ReadLE32(masterKey.key.GetPubKey().GetID().begin()));
- } else { // Single pubkeys get the master fingerprint of themselves
- keypath.insert(keypath.begin(), ReadLE32(vchPubKey.GetID().begin()));
- }
- hd_keypaths.emplace(vchPubKey, keypath);
+ hd_keypaths.emplace(vchPubKey, std::move(info));
}
bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const CTransaction* txConst, int sighash_type, bool sign, bool bip32derivs)
@@ -3937,28 +3880,7 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Specified Sighash and sighash in PSBT do not match.");
}
- SignatureData sigdata;
- if (sign) {
- complete &= SignPSBTInput(*pwallet, *psbtx.tx, input, sigdata, i, sighash_type);
- } else {
- complete &= SignPSBTInput(PublicOnlySigningProvider(pwallet), *psbtx.tx, input, sigdata, i, sighash_type);
- }
-
- if (it != pwallet->mapWallet.end()) {
- // Drop the unnecessary UTXO if we added both from the wallet.
- if (sigdata.witness) {
- input.non_witness_utxo = nullptr;
- } else {
- input.witness_utxo.SetNull();
- }
- }
-
- // Get public key paths
- if (bip32derivs) {
- for (const auto& pubkey_it : sigdata.misc_pubkeys) {
- AddKeypathToMap(pwallet, pubkey_it.first, input.hd_keypaths);
- }
- }
+ complete &= SignPSBTInput(HidingSigningProvider(pwallet, !sign, !bip32derivs), *psbtx.tx, input, i, sighash_type);
}
// Fill in the bip32 keypaths and redeemscripts for the outputs so that hardware wallets can identify change
@@ -3971,15 +3893,8 @@ bool FillPSBT(const CWallet* pwallet, PartiallySignedTransaction& psbtx, const C
psbt_out.FillSignatureData(sigdata);
MutableTransactionSignatureCreator creator(psbtx.tx.get_ptr(), 0, out.nValue, 1);
- ProduceSignature(*pwallet, creator, out.scriptPubKey, sigdata);
+ ProduceSignature(HidingSigningProvider(pwallet, true, !bip32derivs), creator, out.scriptPubKey, sigdata);
psbt_out.FromSignatureData(sigdata);
-
- // Get public key paths
- if (bip32derivs) {
- for (const auto& pubkey_it : sigdata.misc_pubkeys) {
- AddKeypathToMap(pwallet, pubkey_it.first, psbt_out.hd_keypaths);
- }
- }
}
return complete;
}
@@ -4153,7 +4068,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
const CTransaction txConst(*psbtx.tx);
// Fill transaction with out data but don't sign
- bool bip32derivs = request.params[4].isNull() ? false : request.params[5].get_bool();
+ bool bip32derivs = request.params[4].isNull() ? false : request.params[4].get_bool();
FillPSBT(pwallet, psbtx, &txConst, 1, false, bip32derivs);
// Serialize the PSBT
diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp
index 61c3fa94a6..526f2d983f 100644
--- a/src/wallet/test/psbt_wallet_tests.cpp
+++ b/src/wallet/test/psbt_wallet_tests.cpp
@@ -13,8 +13,6 @@
#include <test/test_bitcoin.h>
#include <wallet/test/wallet_test_fixture.h>
-extern bool ParseHDKeypath(std::string keypath_str, std::vector<uint32_t>& keypath);
-
BOOST_FIXTURE_TEST_SUITE(psbt_wallet_tests, WalletTestingSetup)
BOOST_AUTO_TEST_CASE(psbt_updater_test)
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index d0857bcb72..913334a767 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -4469,3 +4469,29 @@ std::vector<OutputGroup> CWallet::GroupOutputs(const std::vector<COutput>& outpu
}
return groups;
}
+
+bool CWallet::GetKeyOrigin(const CKeyID& keyID, KeyOriginInfo& info) const
+{
+ CKeyMetadata meta;
+ {
+ LOCK(cs_wallet);
+ auto it = mapKeyMetadata.find(keyID);
+ if (it != mapKeyMetadata.end()) {
+ meta = it->second;
+ }
+ }
+ if (!meta.hdKeypath.empty()) {
+ if (!ParseHDKeypath(meta.hdKeypath, info.path)) return false;
+ // Get the proper master key id
+ CKey key;
+ GetKey(meta.hd_seed_id, key);
+ CExtKey masterKey;
+ masterKey.SetSeed(key.begin(), key.size());
+ // Compute identifier
+ CKeyID masterid = masterKey.key.GetPubKey().GetID();
+ std::copy(masterid.begin(), masterid.begin() + 4, info.fingerprint);
+ } else { // Single pubkeys get the master fingerprint of themselves
+ std::copy(keyID.begin(), keyID.begin() + 4, info.fingerprint);
+ }
+ return true;
+}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 15062680de..5f550319ed 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -1218,6 +1218,8 @@ public:
LogPrintf(("%s " + fmt).c_str(), GetDisplayName(), parameters...);
};
+ /** Implement lookup of key origin information through wallet key metadata. */
+ bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;
};
/** A key allocated from the key pool. */
diff --git a/test/functional/combine_logs.py b/test/functional/combine_logs.py
index 91b6415a7c..3759913e44 100755
--- a/test/functional/combine_logs.py
+++ b/test/functional/combine_logs.py
@@ -13,7 +13,7 @@ import re
import sys
# Matches on the date format at the start of the log event
-TIMESTAMP_PATTERN = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z")
+TIMESTAMP_PATTERN = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{6})?Z")
LogEvent = namedtuple('LogEvent', ['timestamp', 'source', 'event'])
@@ -75,11 +75,17 @@ def get_log_events(source, logfile):
if time_match:
if event:
yield LogEvent(timestamp=timestamp, source=source, event=event.rstrip())
- event = line
timestamp = time_match.group()
+ if time_match.group(1) is None:
+ # timestamp does not have microseconds. Add zeroes.
+ timestamp_micro = timestamp.replace("Z", ".000000Z")
+ line = line.replace(timestamp, timestamp_micro)
+ timestamp = timestamp_micro
+ event = line
# if it doesn't have a timestamp, it's a continuation line of the previous log.
else:
- event += "\n" + line
+ # Add the line. Prefix with space equivalent to the source + timestamp so log lines are aligned
+ event += " " + line
# Flush the final event
yield LogEvent(timestamp=timestamp, source=source, event=event.rstrip())
except FileNotFoundError:
@@ -98,7 +104,11 @@ def print_logs(log_events, color=False, html=False):
colors["reset"] = "\033[0m" # Reset font color
for event in log_events:
- print("{0} {1: <5} {2} {3}".format(colors[event.source.rstrip()], event.source, event.event, colors["reset"]))
+ lines = event.event.splitlines()
+ print("{0} {1: <5} {2} {3}".format(colors[event.source.rstrip()], event.source, lines[0], colors["reset"]))
+ if len(lines) > 1:
+ for line in lines[1:]:
+ print("{0}{1}{2}".format(colors[event.source.rstrip()], line, colors["reset"]))
else:
try:
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index f847a01e59..d558de5fe1 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -143,17 +143,19 @@ class PSBTTest(BitcoinTestFramework):
# replaceable arg
block_height = self.nodes[0].getblockcount()
unspent = self.nodes[0].listunspent()[0]
- psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height+2, {"replaceable":True})
+ psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height+2, {"replaceable":True}, False)
decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"])
- for tx_in in decoded_psbt["tx"]["vin"]:
+ for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"], decoded_psbt["inputs"]):
assert_equal(tx_in["sequence"], MAX_BIP125_RBF_SEQUENCE)
+ assert "bip32_derivs" not in psbt_in
assert_equal(decoded_psbt["tx"]["locktime"], block_height+2)
# Same construction with only locktime set
- psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height)
+ psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}], block_height, {}, True)
decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"])
- for tx_in in decoded_psbt["tx"]["vin"]:
+ for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"], decoded_psbt["inputs"]):
assert tx_in["sequence"] > MAX_BIP125_RBF_SEQUENCE
+ assert "bip32_derivs" in psbt_in
assert_equal(decoded_psbt["tx"]["locktime"], block_height)
# Same construction without optional arguments
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index 1e3ada26f8..8169f2b981 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -358,7 +358,7 @@ class RawTransactionsTest(BitcoinTestFramework):
# decoderawtransaction tests
# witness transaction
- encrawtx = "010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000000000000"
+ encrawtx = "010000000001010000000000000072c1a6a246ae63f74f931e8365e15a089c68d61900000000000000000000ffffffff0100e1f50500000000000102616100000000"
decrawtx = self.nodes[0].decoderawtransaction(encrawtx, True) # decode as witness transaction
assert_equal(decrawtx['vout'][0]['value'], Decimal('1.00000000'))
assert_raises_rpc_error(-22, 'TX decode failed', self.nodes[0].decoderawtransaction, encrawtx, False) # force decode as non-witness transaction
diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh
index 8f7a1fd76b..346829e24b 100755
--- a/test/lint/lint-includes.sh
+++ b/test/lint/lint-includes.sh
@@ -47,7 +47,6 @@ fi
EXPECTED_BOOST_INCLUDES=(
boost/algorithm/string.hpp
- boost/algorithm/string/case_conv.hpp
boost/algorithm/string/classification.hpp
boost/algorithm/string/replace.hpp
boost/algorithm/string/split.hpp
@@ -57,7 +56,6 @@ EXPECTED_BOOST_INCLUDES=(
boost/filesystem.hpp
boost/filesystem/detail/utf8_codecvt_facet.hpp
boost/filesystem/fstream.hpp
- boost/interprocess/sync/file_lock.hpp
boost/multi_index/hashed_index.hpp
boost/multi_index/ordered_index.hpp
boost/multi_index/sequenced_index.hpp
diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh
index cbe1143bd0..a5b97ca1e9 100755
--- a/test/lint/lint-locale-dependence.sh
+++ b/test/lint/lint-locale-dependence.sh
@@ -11,11 +11,9 @@ KNOWN_VIOLATIONS=(
"src/dbwrapper.cpp:.*vsnprintf"
"src/httprpc.cpp.*trim"
"src/init.cpp:.*atoi"
- "src/netbase.cpp.*to_lower"
"src/qt/rpcconsole.cpp:.*atoi"
"src/qt/rpcconsole.cpp:.*isdigit"
"src/rest.cpp:.*strtol"
- "src/rpc/server.cpp.*to_upper"
"src/test/dbwrapper_tests.cpp:.*snprintf"
"src/test/getarg_tests.cpp.*split"
"src/torcontrol.cpp:.*atoi"