diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/qt/signverifymessagedialog.cpp | 89 | ||||
-rw-r--r-- | src/rpc/misc.cpp | 42 | ||||
-rw-r--r-- | src/test/util_tests.cpp | 110 | ||||
-rw-r--r-- | src/util/message.cpp | 78 | ||||
-rw-r--r-- | src/util/message.h | 68 | ||||
-rw-r--r-- | src/util/time.cpp | 14 | ||||
-rw-r--r-- | src/util/validation.cpp | 2 | ||||
-rw-r--r-- | src/util/validation.h | 2 | ||||
-rw-r--r-- | src/wallet/psbtwallet.h | 2 | ||||
-rw-r--r-- | src/wallet/rpcwallet.cpp | 22 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 10 | ||||
-rw-r--r-- | src/wallet/wallet.h | 4 |
13 files changed, 346 insertions, 99 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 6edd5e75b7..eac7b38e03 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -220,6 +220,7 @@ BITCOIN_CORE_H = \ util/system.h \ util/macros.h \ util/memory.h \ + util/message.h \ util/moneystr.h \ util/rbf.h \ util/settings.h \ @@ -517,6 +518,7 @@ libbitcoin_util_a_SOURCES = \ util/error.cpp \ util/fees.cpp \ util/system.cpp \ + util/message.cpp \ util/moneystr.cpp \ util/rbf.cpp \ util/settings.cpp \ diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 5f2836cc75..883dcecf9a 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -11,7 +11,7 @@ #include <qt/walletmodel.h> #include <key_io.h> -#include <util/validation.h> // For strMessageMagic +#include <util/message.h> // For MessageSign(), MessageVerify() #include <wallet/wallet.h> #include <vector> @@ -141,13 +141,10 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() return; } - CHashWriter ss(SER_GETHASH, 0); - ss << strMessageMagic; - ss << ui->messageIn_SM->document()->toPlainText().toStdString(); + const std::string& message = ui->messageIn_SM->document()->toPlainText().toStdString(); + std::string signature; - std::vector<unsigned char> vchSig; - if (!key.SignCompact(ss.GetHash(), vchSig)) - { + if (!MessageSign(key, message, signature)) { ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signing failed.") + QString("</nobr>")); return; @@ -156,7 +153,7 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked() ui->statusLabel_SM->setStyleSheet("QLabel { color: green; }"); ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signed.") + QString("</nobr>")); - ui->signatureOut_SM->setText(QString::fromStdString(EncodeBase64(vchSig.data(), vchSig.size()))); + ui->signatureOut_SM->setText(QString::fromStdString(signature)); } void SignVerifyMessageDialog::on_copySignatureButton_SM_clicked() @@ -189,51 +186,57 @@ void SignVerifyMessageDialog::on_addressBookButton_VM_clicked() void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked() { - CTxDestination destination = DecodeDestination(ui->addressIn_VM->text().toStdString()); - if (!IsValidDestination(destination)) { + const std::string& address = ui->addressIn_VM->text().toStdString(); + const std::string& signature = ui->signatureIn_VM->text().toStdString(); + const std::string& message = ui->messageIn_VM->document()->toPlainText().toStdString(); + + const auto result = MessageVerify(address, signature, message); + + if (result == MessageVerificationResult::OK) { + ui->statusLabel_VM->setStyleSheet("QLabel { color: green; }"); + } else { ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); - ui->statusLabel_VM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); - return; } - if (!boost::get<PKHash>(&destination)) { + + switch (result) { + case MessageVerificationResult::OK: + ui->statusLabel_VM->setText( + QString("<nobr>") + tr("Message verified.") + QString("</nobr>") + ); + return; + case MessageVerificationResult::ERR_INVALID_ADDRESS: + ui->statusLabel_VM->setText( + tr("The entered address is invalid.") + QString(" ") + + tr("Please check the address and try again.") + ); + return; + case MessageVerificationResult::ERR_ADDRESS_NO_KEY: ui->addressIn_VM->setValid(false); - ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); - ui->statusLabel_VM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again.")); + ui->statusLabel_VM->setText( + tr("The entered address does not refer to a key.") + QString(" ") + + tr("Please check the address and try again.") + ); return; - } - - bool fInvalid = false; - std::vector<unsigned char> vchSig = DecodeBase64(ui->signatureIn_VM->text().toStdString().c_str(), &fInvalid); - - if (fInvalid) - { + case MessageVerificationResult::ERR_MALFORMED_SIGNATURE: ui->signatureIn_VM->setValid(false); - ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); - ui->statusLabel_VM->setText(tr("The signature could not be decoded.") + QString(" ") + tr("Please check the signature and try again.")); + ui->statusLabel_VM->setText( + tr("The signature could not be decoded.") + QString(" ") + + tr("Please check the signature and try again.") + ); return; - } - - CHashWriter ss(SER_GETHASH, 0); - ss << strMessageMagic; - ss << ui->messageIn_VM->document()->toPlainText().toStdString(); - - CPubKey pubkey; - if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) - { + case MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED: ui->signatureIn_VM->setValid(false); - ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); - ui->statusLabel_VM->setText(tr("The signature did not match the message digest.") + QString(" ") + tr("Please check the signature and try again.")); + ui->statusLabel_VM->setText( + tr("The signature did not match the message digest.") + QString(" ") + + tr("Please check the signature and try again.") + ); return; - } - - if (!(CTxDestination(PKHash(pubkey)) == destination)) { - ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }"); - ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>")); + case MessageVerificationResult::ERR_NOT_SIGNED: + ui->statusLabel_VM->setText( + QString("<nobr>") + tr("Message verification failed.") + QString("</nobr>") + ); return; } - - ui->statusLabel_VM->setStyleSheet("QLabel { color: green; }"); - ui->statusLabel_VM->setText(QString("<nobr>") + tr("Message verified.") + QString("</nobr>")); } void SignVerifyMessageDialog::on_clearButton_VM_clicked() diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index c8711f44d4..4279756f4d 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -13,9 +13,9 @@ #include <scheduler.h> #include <script/descriptor.h> #include <util/check.h> +#include <util/message.h> // For MessageSign(), MessageVerify() #include <util/strencodings.h> #include <util/system.h> -#include <util/validation.h> #include <stdint.h> #include <tuple> @@ -278,31 +278,21 @@ static UniValue verifymessage(const JSONRPCRequest& request) std::string strSign = request.params[1].get_str(); std::string strMessage = request.params[2].get_str(); - CTxDestination destination = DecodeDestination(strAddress); - if (!IsValidDestination(destination)) { + switch (MessageVerify(strAddress, strSign, strMessage)) { + case MessageVerificationResult::ERR_INVALID_ADDRESS: throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); - } - - const PKHash *pkhash = boost::get<PKHash>(&destination); - if (!pkhash) { + case MessageVerificationResult::ERR_ADDRESS_NO_KEY: throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); - } - - bool fInvalid = false; - std::vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid); - - if (fInvalid) + case MessageVerificationResult::ERR_MALFORMED_SIGNATURE: throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding"); - - CHashWriter ss(SER_GETHASH, 0); - ss << strMessageMagic; - ss << strMessage; - - CPubKey pubkey; - if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) + case MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED: + case MessageVerificationResult::ERR_NOT_SIGNED: return false; + case MessageVerificationResult::OK: + return true; + } - return (pubkey.GetID() == *pkhash); + return false; } static UniValue signmessagewithprivkey(const JSONRPCRequest& request) @@ -334,15 +324,13 @@ static UniValue signmessagewithprivkey(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); } - CHashWriter ss(SER_GETHASH, 0); - ss << strMessageMagic; - ss << strMessage; + std::string signature; - std::vector<unsigned char> vchSig; - if (!key.SignCompact(ss.GetHash(), vchSig)) + if (!MessageSign(key, strMessage, signature)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed"); + } - return EncodeBase64(vchSig.data(), vchSig.size()); + return signature; } static UniValue setmocktime(const JSONRPCRequest& request) diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index 42c2c50fa5..f86e713676 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -5,10 +5,14 @@ #include <util/system.h> #include <clientversion.h> +#include <hash.h> // For Hash() +#include <key.h> // For CKey #include <optional.h> #include <sync.h> #include <test/util/setup_common.h> #include <test/util/str.h> +#include <uint256.h> +#include <util/message.h> // For MessageSign(), MessageVerify(), MESSAGE_MAGIC #include <util/moneystr.h> #include <util/strencodings.h> #include <util/string.h> @@ -16,6 +20,7 @@ #include <util/spanparsing.h> #include <util/vector.h> +#include <array> #include <stdint.h> #include <thread> #include <univalue.h> @@ -2025,4 +2030,109 @@ BOOST_AUTO_TEST_CASE(test_tracked_vector) BOOST_CHECK_EQUAL(v8[2].copies, 0); } +BOOST_AUTO_TEST_CASE(message_sign) +{ + const std::array<unsigned char, 32> privkey_bytes = { + // just some random data + // derived address from this private key: 15CRxFdyRpGZLW9w8HnHvVduizdL5jKNbs + 0xD9, 0x7F, 0x51, 0x08, 0xF1, 0x1C, 0xDA, 0x6E, + 0xEE, 0xBA, 0xAA, 0x42, 0x0F, 0xEF, 0x07, 0x26, + 0xB1, 0xF8, 0x98, 0x06, 0x0B, 0x98, 0x48, 0x9F, + 0xA3, 0x09, 0x84, 0x63, 0xC0, 0x03, 0x28, 0x66 + }; + + const std::string message = "Trust no one"; + + const std::string expected_signature = + "IPojfrX2dfPnH26UegfbGQQLrdK844DlHq5157/P6h57WyuS/Qsl+h/WSVGDF4MUi4rWSswW38oimDYfNNUBUOk="; + + CKey privkey; + std::string generated_signature; + + BOOST_REQUIRE_MESSAGE(!privkey.IsValid(), + "Confirm the private key is invalid"); + + BOOST_CHECK_MESSAGE(!MessageSign(privkey, message, generated_signature), + "Sign with an invalid private key"); + + privkey.Set(privkey_bytes.begin(), privkey_bytes.end(), true); + + BOOST_REQUIRE_MESSAGE(privkey.IsValid(), + "Confirm the private key is valid"); + + BOOST_CHECK_MESSAGE(MessageSign(privkey, message, generated_signature), + "Sign with a valid private key"); + + BOOST_CHECK_EQUAL(expected_signature, generated_signature); +} + +BOOST_AUTO_TEST_CASE(message_verify) +{ + BOOST_CHECK_EQUAL( + MessageVerify( + "invalid address", + "signature should be irrelevant", + "message too"), + MessageVerificationResult::ERR_INVALID_ADDRESS); + + BOOST_CHECK_EQUAL( + MessageVerify( + "3B5fQsEXEaV8v6U3ejYc8XaKXAkyQj2MjV", + "signature should be irrelevant", + "message too"), + MessageVerificationResult::ERR_ADDRESS_NO_KEY); + + BOOST_CHECK_EQUAL( + MessageVerify( + "1KqbBpLy5FARmTPD4VZnDDpYjkUvkr82Pm", + "invalid signature, not in base64 encoding", + "message should be irrelevant"), + MessageVerificationResult::ERR_MALFORMED_SIGNATURE); + + BOOST_CHECK_EQUAL( + MessageVerify( + "1KqbBpLy5FARmTPD4VZnDDpYjkUvkr82Pm", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "message should be irrelevant"), + MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED); + + BOOST_CHECK_EQUAL( + MessageVerify( + "15CRxFdyRpGZLW9w8HnHvVduizdL5jKNbs", + "IPojfrX2dfPnH26UegfbGQQLrdK844DlHq5157/P6h57WyuS/Qsl+h/WSVGDF4MUi4rWSswW38oimDYfNNUBUOk=", + "I never signed this"), + MessageVerificationResult::ERR_NOT_SIGNED); + + BOOST_CHECK_EQUAL( + MessageVerify( + "15CRxFdyRpGZLW9w8HnHvVduizdL5jKNbs", + "IPojfrX2dfPnH26UegfbGQQLrdK844DlHq5157/P6h57WyuS/Qsl+h/WSVGDF4MUi4rWSswW38oimDYfNNUBUOk=", + "Trust no one"), + MessageVerificationResult::OK); + + BOOST_CHECK_EQUAL( + MessageVerify( + "11canuhp9X2NocwCq7xNrQYTmUgZAnLK3", + "IIcaIENoYW5jZWxsb3Igb24gYnJpbmsgb2Ygc2Vjb25kIGJhaWxvdXQgZm9yIGJhbmtzIAaHRtbCeDZINyavx14=", + "Trust me"), + MessageVerificationResult::OK); +} + +BOOST_AUTO_TEST_CASE(message_hash) +{ + const std::string unsigned_tx = "..."; + const std::string prefixed_message = + std::string(1, (char)MESSAGE_MAGIC.length()) + + MESSAGE_MAGIC + + std::string(1, (char)unsigned_tx.length()) + + unsigned_tx; + + const uint256 signature_hash = Hash(unsigned_tx.begin(), unsigned_tx.end()); + const uint256 message_hash1 = Hash(prefixed_message.begin(), prefixed_message.end()); + const uint256 message_hash2 = MessageHash(unsigned_tx); + + BOOST_CHECK_EQUAL(message_hash1, message_hash2); + BOOST_CHECK_NE(message_hash1, signature_hash); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/util/message.cpp b/src/util/message.cpp new file mode 100644 index 0000000000..17603a43d2 --- /dev/null +++ b/src/util/message.cpp @@ -0,0 +1,78 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-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 <hash.h> // For CHashWriter +#include <key.h> // For CKey +#include <key_io.h> // For DecodeDestination() +#include <pubkey.h> // For CPubKey +#include <script/standard.h> // For CTxDestination, IsValidDestination(), PKHash +#include <serialize.h> // For SER_GETHASH +#include <util/message.h> +#include <util/strencodings.h> // For DecodeBase64() + +#include <string> +#include <vector> + +/** + * Text used to signify that a signed message follows and to prevent + * inadvertently signing a transaction. + */ +const std::string MESSAGE_MAGIC = "Bitcoin Signed Message:\n"; + +MessageVerificationResult MessageVerify( + const std::string& address, + const std::string& signature, + const std::string& message) +{ + CTxDestination destination = DecodeDestination(address); + if (!IsValidDestination(destination)) { + return MessageVerificationResult::ERR_INVALID_ADDRESS; + } + + if (boost::get<PKHash>(&destination) == nullptr) { + return MessageVerificationResult::ERR_ADDRESS_NO_KEY; + } + + bool invalid = false; + std::vector<unsigned char> signature_bytes = DecodeBase64(signature.c_str(), &invalid); + if (invalid) { + return MessageVerificationResult::ERR_MALFORMED_SIGNATURE; + } + + CPubKey pubkey; + if (!pubkey.RecoverCompact(MessageHash(message), signature_bytes)) { + return MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED; + } + + if (!(CTxDestination(PKHash(pubkey)) == destination)) { + return MessageVerificationResult::ERR_NOT_SIGNED; + } + + return MessageVerificationResult::OK; +} + +bool MessageSign( + const CKey& privkey, + const std::string& message, + std::string& signature) +{ + std::vector<unsigned char> signature_bytes; + + if (!privkey.SignCompact(MessageHash(message), signature_bytes)) { + return false; + } + + signature = EncodeBase64(signature_bytes.data(), signature_bytes.size()); + + return true; +} + +uint256 MessageHash(const std::string& message) +{ + CHashWriter hasher(SER_GETHASH, 0); + hasher << MESSAGE_MAGIC << message; + + return hasher.GetHash(); +} diff --git a/src/util/message.h b/src/util/message.h new file mode 100644 index 0000000000..01fd14ce2d --- /dev/null +++ b/src/util/message.h @@ -0,0 +1,68 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-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. + +#ifndef BITCOIN_UTIL_MESSAGE_H +#define BITCOIN_UTIL_MESSAGE_H + +#include <key.h> // For CKey +#include <uint256.h> + +#include <string> + +extern const std::string MESSAGE_MAGIC; + +/** The result of a signed message verification. + * Message verification takes as an input: + * - address (with whose private key the message is supposed to have been signed) + * - signature + * - message + */ +enum class MessageVerificationResult { + //! The provided address is invalid. + ERR_INVALID_ADDRESS, + + //! The provided address is valid but does not refer to a public key. + ERR_ADDRESS_NO_KEY, + + //! The provided signature couldn't be parsed (maybe invalid base64). + ERR_MALFORMED_SIGNATURE, + + //! A public key could not be recovered from the provided signature and message. + ERR_PUBKEY_NOT_RECOVERED, + + //! The message was not signed with the private key of the provided address. + ERR_NOT_SIGNED, + + //! The message verification was successful. + OK +}; + +/** Verify a signed message. + * @param[in] address Signer's bitcoin address, it must refer to a public key. + * @param[in] signature The signature in base64 format. + * @param[in] message The message that was signed. + * @return result code */ +MessageVerificationResult MessageVerify( + const std::string& address, + const std::string& signature, + const std::string& message); + +/** Sign a message. + * @param[in] privkey Private key to sign with. + * @param[in] message The message to sign. + * @param[out] signature Signature, base64 encoded, only set if true is returned. + * @return true if signing was successful. */ +bool MessageSign( + const CKey& privkey, + const std::string& message, + std::string& signature); + +/** + * Hashes a message for signing and verification in a manner that prevents + * inadvertently signing a transaction. + */ +uint256 MessageHash(const std::string& message); + +#endif // BITCOIN_UTIL_MESSAGE_H diff --git a/src/util/time.cpp b/src/util/time.cpp index 2afff2626b..f33966f149 100644 --- a/src/util/time.cpp +++ b/src/util/time.cpp @@ -94,10 +94,12 @@ std::string FormatISO8601DateTime(int64_t nTime) { struct tm ts; time_t time_val = nTime; #ifdef _MSC_VER - gmtime_s(&ts, &time_val); + if (gmtime_s(&ts, &time_val) != 0) { #else - gmtime_r(&time_val, &ts); + if (gmtime_r(&time_val, &ts) == nullptr) { #endif + return {}; + } return strprintf("%04i-%02i-%02iT%02i:%02i:%02iZ", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec); } @@ -105,10 +107,12 @@ std::string FormatISO8601Date(int64_t nTime) { struct tm ts; time_t time_val = nTime; #ifdef _MSC_VER - gmtime_s(&ts, &time_val); + if (gmtime_s(&ts, &time_val) != 0) { #else - gmtime_r(&time_val, &ts); + if (gmtime_r(&time_val, &ts) == nullptr) { #endif + return {}; + } return strprintf("%04i-%02i-%02i", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday); } @@ -124,4 +128,4 @@ int64_t ParseISO8601DateTime(const std::string& str) if (ptime.is_not_a_date_time() || epoch > ptime) return 0; return (ptime - epoch).total_seconds(); -}
\ No newline at end of file +} diff --git a/src/util/validation.cpp b/src/util/validation.cpp index 89bc6665a4..ffbee21aeb 100644 --- a/src/util/validation.cpp +++ b/src/util/validation.cpp @@ -21,5 +21,3 @@ std::string FormatStateMessage(const ValidationState &state) return state.GetRejectReason(); } - -const std::string strMessageMagic = "Bitcoin Signed Message:\n"; diff --git a/src/util/validation.h b/src/util/validation.h index da2cf9f102..5ee260a055 100644 --- a/src/util/validation.h +++ b/src/util/validation.h @@ -13,6 +13,4 @@ class ValidationState; /** Convert ValidationState to a human-readable message for logging */ std::string FormatStateMessage(const ValidationState &state); -extern const std::string strMessageMagic; - #endif // BITCOIN_UTIL_VALIDATION_H diff --git a/src/wallet/psbtwallet.h b/src/wallet/psbtwallet.h index b35a0a58d1..8285bb901c 100644 --- a/src/wallet/psbtwallet.h +++ b/src/wallet/psbtwallet.h @@ -27,6 +27,6 @@ NODISCARD TransactionError FillPSBT(const CWallet* pwallet, bool& complete, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, - bool bip32derivs = false); + bool bip32derivs = true); #endif // BITCOIN_WALLET_PSBTWALLET_H diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index e8905e781c..0a9b739fb9 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -19,11 +19,11 @@ #include <script/sign.h> #include <util/bip32.h> #include <util/fees.h> +#include <util/message.h> // For MessageSign() #include <util/moneystr.h> #include <util/string.h> #include <util/system.h> #include <util/url.h> -#include <util/validation.h> #include <wallet/coincontrol.h> #include <wallet/feebumper.h> #include <wallet/psbtwallet.h> @@ -576,15 +576,13 @@ static UniValue signmessage(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_ERROR, "Private key not available"); } - CHashWriter ss(SER_GETHASH, 0); - ss << strMessageMagic; - ss << strMessage; + std::string signature; - std::vector<unsigned char> vchSig; - if (!key.SignCompact(ss.GetHash(), vchSig)) + if (!MessageSign(key, strMessage, signature)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed"); + } - return EncodeBase64(vchSig.data(), vchSig.size()); + return signature; } static UniValue getreceivedbyaddress(const JSONRPCRequest& request) @@ -2925,7 +2923,7 @@ static UniValue listunspent(const JSONRPCRequest& request) CTxDestination address; const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey; bool fValidAddress = ExtractDestination(scriptPubKey, address); - bool reused = avoid_reuse && pwallet->IsUsedDestination(out.tx->GetHash(), out.i); + bool reused = avoid_reuse && pwallet->IsSpentKey(out.tx->GetHash(), out.i); if (destinations.size() && (!fValidAddress || !destinations.count(address))) continue; @@ -4068,7 +4066,7 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request) " \"ALL|ANYONECANPAY\"\n" " \"NONE|ANYONECANPAY\"\n" " \"SINGLE|ANYONECANPAY\""}, - {"bip32derivs", RPCArg::Type::BOOL, /* default */ "false", "If true, includes the BIP 32 derivation paths for public keys if we know them"}, + {"bip32derivs", RPCArg::Type::BOOL, /* default */ "true", "Include BIP 32 derivation paths for public keys if we know them"}, }, RPCResult{ "{ (json object)\n" @@ -4095,7 +4093,7 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request) // Fill transaction with our data and also sign bool sign = request.params[1].isNull() ? true : request.params[1].get_bool(); - bool bip32derivs = request.params[3].isNull() ? false : request.params[3].get_bool(); + bool bip32derivs = request.params[3].isNull() ? true : request.params[3].get_bool(); bool complete = true; const TransactionError err = FillPSBT(pwallet, psbtx, complete, nHashType, sign, bip32derivs); if (err != TransactionError::OK) { @@ -4178,7 +4176,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request) " \"CONSERVATIVE\""}, }, "options"}, - {"bip32derivs", RPCArg::Type::BOOL, /* default */ "false", "If true, includes the BIP 32 derivation paths for public keys if we know them"}, + {"bip32derivs", RPCArg::Type::BOOL, /* default */ "true", "Include BIP 32 derivation paths for public keys if we know them"}, }, RPCResult{ "{\n" @@ -4217,7 +4215,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request) PartiallySignedTransaction psbtx(rawTx); // Fill transaction with out data but don't sign - bool bip32derivs = request.params[4].isNull() ? false : request.params[4].get_bool(); + bool bip32derivs = request.params[4].isNull() ? true : request.params[4].get_bool(); bool complete = true; const TransactionError err = FillPSBT(pwallet, psbtx, complete, 1, false, bip32derivs); if (err != TransactionError::OK) { diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 6b9f53f7c5..02fe59b601 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -714,7 +714,7 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash) return success; } -void CWallet::SetUsedDestinationState(WalletBatch& batch, const uint256& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations) +void CWallet::SetSpentKeyState(WalletBatch& batch, const uint256& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations) { AssertLockHeld(cs_wallet); const CWalletTx* srctx = GetWalletTx(hash); @@ -734,7 +734,7 @@ void CWallet::SetUsedDestinationState(WalletBatch& batch, const uint256& hash, u } } -bool CWallet::IsUsedDestination(const uint256& hash, unsigned int n) const +bool CWallet::IsSpentKey(const uint256& hash, unsigned int n) const { AssertLockHeld(cs_wallet); CTxDestination dst; @@ -777,7 +777,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose) for (const CTxIn& txin : wtxIn.tx->vin) { const COutPoint& op = txin.prevout; - SetUsedDestinationState(batch, op.hash, op.n, true, tx_destinations); + SetSpentKeyState(batch, op.hash, op.n, true, tx_destinations); } MarkDestinationsDirty(tx_destinations); @@ -1878,7 +1878,7 @@ CAmount CWalletTx::GetAvailableCredit(bool fUseCache, const isminefilter& filter uint256 hashTx = GetHash(); for (unsigned int i = 0; i < tx->vout.size(); i++) { - if (!pwallet->IsSpent(hashTx, i) && (allow_used_addresses || !pwallet->IsUsedDestination(hashTx, i))) { + if (!pwallet->IsSpent(hashTx, i) && (allow_used_addresses || !pwallet->IsSpentKey(hashTx, i))) { const CTxOut &txout = tx->vout[i]; nCredit += pwallet->GetCredit(txout, filter); if (!MoneyRange(nCredit)) @@ -2168,7 +2168,7 @@ void CWallet::AvailableCoins(interfaces::Chain::Lock& locked_chain, std::vector< continue; } - if (!allow_used_addresses && IsUsedDestination(wtxid, i)) { + if (!allow_used_addresses && IsSpentKey(wtxid, i)) { continue; } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index a918bb8833..6c1c3040c2 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -817,8 +817,8 @@ public: bool IsSpent(const uint256& hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); // Whether this or any known UTXO with the same single key has been spent. - bool IsUsedDestination(const uint256& hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - void SetUsedDestinationState(WalletBatch& batch, const uint256& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + bool IsSpentKey(const uint256& hash, unsigned int n) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + void SetSpentKeyState(WalletBatch& batch, const uint256& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); std::vector<OutputGroup> GroupOutputs(const std::vector<COutput>& outputs, bool single_coin) const; |