From f812de4e660a999c09707ed878bfbffcdb8dbef8 Mon Sep 17 00:00:00 2001 From: Samuel Dobson Date: Tue, 10 Mar 2020 08:56:38 +1300 Subject: [PATCH] Merge #18115: wallet: Pass in transactions and messages for signing instead of exporting the private keys d2774c09cfcc6c5c967d40bb094eabc8c0bdb6bf Clear any input_errors for an input after it is signed (Andrew Chow) dc174881ad8498a6905ba282a48077bc5c8037a7 Replace GetSigningProvider with GetSolvingProvider (Andrew Chow) 6a9c429084b40356aa36aa67992da35f61c2f6a2 Move direct calls to MessageSign into new SignMessage functions in CWallet and ScriptPubKeyMan (Andrew Chow) 82a30fade70a2a95c2bbeac4aa06dafda600479d Move key and script filling and signing from CWallet::FillPSBT to ScriptPubKeyMan::FillPSBT (Andrew Chow) 3d70dd99f9f74eef70b19ff6f6f850adc0d5ef8f Move FillPSBT to be a member of CWallet (Andrew Chow) a4af324d15c1ee43c2abd11a304ae18c7ee82eb0 Use CWallet::SignTransaction in CreateTransaction and signrawtransactionwithwallet (Andrew Chow) f37de927442d3f024926a66c436d59e391c8696a Implement CWallet::SignTransaction using ScriptPubKeyMan::SignTransaction (Andrew Chow) d999dd588cab0ff479bc7bee8c9fc33880265ec6 Add SignTransaction function to ScriptPubKeyMan and LegacyScriptPubKeyMan (Andrew Chow) 2c52b59d0a44a86d94fee4e437978d822862c542 Refactor rawtransaction's SignTransaction into generic SignTransaction function (Andrew Chow) Pull request description: Following #17261, the way to sign transactions, PSBTs, and messages was to use `GetSigningProvider()` and get a `SigningProvider` containing the private keys. However this may not be feasible for future `ScriptPubKeyMan`s, such as for hardware wallets. Instead of exporting a `SigningProvider` containing private keys, we need to pass these things into the `ScriptPubKeyMan` (via `CWallet`) so that they can do whatever is needed internally to sign them. This is largely a refactor as the logic of processing transactions, PSBTs, and messages for is moved into `LegacyScriptPubKeyMan` and `CWallet` instead of being handled by the caller (e.g. `signrawtransaction`). To help with this, I've refactored the 3(!) implementations of a `SignTransaction()` function into one generic one. This function will be called by `signrawtransactionwithkey` and `LegacyScriptPubKeyMan::SignTransaction()`. `CWallet::CreateTransaction()` is changed to call `CWallet::SignTransaction()` which in turn, calls `LegacyScriptPubKeyMan::SignTransaction()`. Other `ScriptPubKeyMan`s may implement `SignTransaction()` differently. `FillPSBT()` is moved to be a member function of `CWallet` and the `psbtwallet.cpp/h` files removed. It is further split so that `CWallet` handles filling the UTXOs while the `ScriptPubKeyMan` handles adding keys, derivation paths, scripts, and signatures. In the end `LegacyScriptPubKeyMan::FillPSBT` still calls `SignPSBTInput`, but the `SigningProvider` is internal to `LegacyScriptPubKeyMan`. Other `ScriptPubKeyMan`s may do something different. A new `SignMessage()` function is added to both `CWallet` and `ScriptPubKeyMan`. Instead of having the caller (i.e. `signmessage` or the sign message dialog) get the private key, hash the message, and sign, `ScriptPubKeyMan` will now handle that (`CWallet` passes through to the `ScriptPubKeyMan`s as it does for many functions). This signing code is thus consolidated into `LegacyScriptPubKeyMan::SignMessage()`, though other `ScriptPubKeyMan`s may implement it differently. Additionally, a `SigningError` enum is introduced for the different errors that we expect to see from `SignMessage()`. Lastly, `GetSigningProvider()` is renamed to `GetPublicSigningProvider()`. It will now only provide pubkeys, key origins, and scripts. `LegacySigningProvider` has it's `GetKey` and `HaveKey` functions changed to only return false. Future implementations should return `HidingSigningProvider`s where private keys are hidden. Other things like `dumpprivkey` and `dumpwallet` are not changed because they directly need and access the `LegacyScriptPubKeyMan` so are not relevant to future changes. ACKs for top commit: instagibbs: reACK https://github.com/bitcoin/bitcoin/pull/18115/commits/d2774c09cfcc6c5c967d40bb094eabc8c0bdb6bf Sjors: re-utACK d2774c09cfcc6c5c967d40bb094eabc8c0bdb6bf meshcollider: re-utACK d2774c09cfcc6c5c967d40bb094eabc8c0bdb6bf Tree-SHA512: 89c83e7e7e9315e283fae145a2264648a9d7f7ace8f3281cb3f44f0b013c988d67ba4fa9726e50c643c0ed921bdd269adaec984840d11acf4a681f3e8a582cc1 --- src/Makefile.am | 2 - src/coinjoin/client.cpp | 4 +- src/interfaces/wallet.cpp | 15 +- src/interfaces/wallet.h | 8 +- src/qt/sendcoinsdialog.cpp | 1 - src/qt/signverifymessagedialog.cpp | 27 ++-- src/rpc/rawtransaction_util.cpp | 4 + src/script/sign.cpp | 3 + src/util/message.cpp | 14 ++ src/util/message.h | 8 + src/wallet/psbtwallet.cpp | 76 --------- src/wallet/psbtwallet.h | 32 ---- src/wallet/rpcwallet.cpp | 54 +++---- src/wallet/scriptpubkeyman.cpp | 64 +++++++- src/wallet/scriptpubkeyman.h | 28 +++- src/wallet/test/psbt_wallet_tests.cpp | 7 +- src/wallet/wallet.cpp | 214 +++++++++++++++++++++++--- src/wallet/wallet.h | 34 +++- 18 files changed, 381 insertions(+), 214 deletions(-) delete mode 100644 src/wallet/psbtwallet.cpp delete mode 100644 src/wallet/psbtwallet.h diff --git a/src/Makefile.am b/src/Makefile.am index bdf8a7dcba..c9b5ab4c4a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -335,7 +335,6 @@ BITCOIN_CORE_H = \ wallet/fees.h \ wallet/ismine.h \ wallet/load.h \ - wallet/psbtwallet.h \ wallet/rpcwallet.h \ wallet/salvage.h \ wallet/scriptpubkeyman.h \ @@ -499,7 +498,6 @@ libbitcoin_wallet_a_SOURCES = \ wallet/db.cpp \ wallet/fees.cpp \ wallet/load.cpp \ - wallet/psbtwallet.cpp \ wallet/rpcdump.cpp \ wallet/rpcwallet.cpp \ wallet/scriptpubkeyman.cpp \ diff --git a/src/coinjoin/client.cpp b/src/coinjoin/client.cpp index c7777d08cf..aaa2ebb571 100644 --- a/src/coinjoin/client.cpp +++ b/src/coinjoin/client.cpp @@ -620,7 +620,7 @@ bool CCoinJoinClientSession::SignFinalTransaction(const CTxMemPool& mempool, con LogPrint(BCLog::COINJOIN, "CCoinJoinClientSession::%s -- Signing my input %i\n", __func__, nMyInputIndex); // TODO we're using amount=0 here but we should use the correct amount. This works because Dash ignores the amount while signing/verifying (only used in Bitcoin/Segwit) - if (!SignSignature(*mixingWallet.GetSigningProvider(prevPubKey), prevPubKey, finalMutableTransaction, nMyInputIndex, 0, int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))) { // changes scriptSig + if (!SignSignature(*mixingWallet.GetSolvingProvider(prevPubKey), prevPubKey, finalMutableTransaction, nMyInputIndex, 0, int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))) { // changes scriptSig LogPrint(BCLog::COINJOIN, "CCoinJoinClientSession::%s -- Unable to sign my own transaction!\n", __func__); // not sure what to do here, it will time out...? } @@ -1541,7 +1541,7 @@ bool CCoinJoinClientSession::CreateCollateralTransaction(CMutableTransaction& tx txCollateral.vout.emplace_back(0, CScript() << OP_RETURN); } - if (!SignSignature(*mixingWallet.GetSigningProvider(txout.scriptPubKey), txout.scriptPubKey, txCollateral, 0, txout.nValue, SIGHASH_ALL)) { + if (!SignSignature(*mixingWallet.GetSolvingProvider(txout.scriptPubKey), txout.scriptPubKey, txCollateral, 0, txout.nValue, SIGHASH_ALL)) { strReason = "Unable to sign collateral transaction!"; return false; } diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index ae29fb5cb3..815e32946c 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include @@ -192,19 +191,15 @@ public: } bool getPubKey(const CScript& script, const CKeyID& address, CPubKey& pub_key) override { - std::unique_ptr provider = m_wallet->GetSigningProvider(script); + std::unique_ptr provider = m_wallet->GetSolvingProvider(script); if (provider) { return provider->GetPubKey(address, pub_key); } return false; } - bool getPrivKey(const CScript& script, const CKeyID& address, CKey& key) override + SigningResult signMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) override { - std::unique_ptr provider = m_wallet->GetSigningProvider(script); - if (provider) { - return provider->GetKey(address, key); - } - return false; + return m_wallet->SignMessage(message, pkhash, str_sig); } bool isSpendable(const CScript& script) override { return m_wallet->IsMine(script) & ISMINE_SPENDABLE; } bool isSpendable(const CTxDestination& dest) override { return m_wallet->IsMine(dest) & ISMINE_SPENDABLE; } @@ -404,9 +399,9 @@ public: bool& complete, int sighash_type = 1 /* SIGHASH_ALL */, bool sign = true, - bool bip32derivs = false) override + bool bip32derivs = false) const override { - return FillPSBT(m_wallet.get(), psbtx, complete, sighash_type, sign, bip32derivs); + return m_wallet->FillPSBT(psbtx, complete, sighash_type, sign, bip32derivs); } WalletBalances getBalances() override { diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index 3f68b9777b..fba448f54c 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -12,7 +12,7 @@ #include