/bitcoin/src/wallet/external_signer_scriptpubkeyman.cpp
Line | Count | Source |
1 | | // Copyright (c) 2020-2022 The Bitcoin Core developers |
2 | | // Distributed under the MIT software license, see the accompanying |
3 | | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
4 | | |
5 | | #include <chainparams.h> |
6 | | #include <common/args.h> |
7 | | #include <common/system.h> |
8 | | #include <external_signer.h> |
9 | | #include <node/types.h> |
10 | | #include <wallet/external_signer_scriptpubkeyman.h> |
11 | | |
12 | | #include <iostream> |
13 | | #include <key_io.h> |
14 | | #include <memory> |
15 | | #include <stdexcept> |
16 | | #include <string> |
17 | | #include <univalue.h> |
18 | | #include <utility> |
19 | | #include <vector> |
20 | | |
21 | | using common::PSBTError; |
22 | | |
23 | | namespace wallet { |
24 | | bool ExternalSignerScriptPubKeyMan::SetupDescriptor(WalletBatch& batch, std::unique_ptr<Descriptor> desc) |
25 | 0 | { |
26 | 0 | LOCK(cs_desc_man); |
27 | 0 | assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)); Branch (27:5): [True: 0, False: 0]
|
28 | 0 | assert(m_storage.IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)); Branch (28:5): [True: 0, False: 0]
|
29 | | |
30 | 0 | int64_t creation_time = GetTime(); |
31 | | |
32 | | // Make the descriptor |
33 | 0 | WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0); |
34 | 0 | m_wallet_descriptor = w_desc; |
35 | | |
36 | | // Store the descriptor |
37 | 0 | if (!batch.WriteDescriptor(GetID(), m_wallet_descriptor)) { Branch (37:9): [True: 0, False: 0]
|
38 | 0 | throw std::runtime_error(std::string(__func__) + ": writing descriptor failed"); |
39 | 0 | } |
40 | | |
41 | | // TopUp |
42 | 0 | TopUpWithDB(batch); |
43 | |
|
44 | 0 | m_storage.UnsetBlankWalletFlag(batch); |
45 | 0 | return true; |
46 | 0 | } |
47 | | |
48 | 0 | ExternalSigner ExternalSignerScriptPubKeyMan::GetExternalSigner() { |
49 | 0 | const std::string command = gArgs.GetArg("-signer", ""); |
50 | 0 | if (command == "") throw std::runtime_error(std::string(__func__) + ": restart bitcoind with -signer=<cmd>"); Branch (50:9): [True: 0, False: 0]
|
51 | 0 | std::vector<ExternalSigner> signers; |
52 | 0 | ExternalSigner::Enumerate(command, signers, Params().GetChainTypeString()); |
53 | 0 | if (signers.empty()) throw std::runtime_error(std::string(__func__) + ": No external signers found"); Branch (53:9): [True: 0, False: 0]
|
54 | | // TODO: add fingerprint argument instead of failing in case of multiple signers. |
55 | 0 | if (signers.size() > 1) throw std::runtime_error(std::string(__func__) + ": More than one external signer found. Please connect only one at a time."); Branch (55:9): [True: 0, False: 0]
|
56 | 0 | return signers[0]; |
57 | 0 | } |
58 | | |
59 | | util::Result<void> ExternalSignerScriptPubKeyMan::DisplayAddress(const CTxDestination& dest, const ExternalSigner &signer) const |
60 | 0 | { |
61 | | // TODO: avoid the need to infer a descriptor from inside a descriptor wallet |
62 | 0 | const CScript& scriptPubKey = GetScriptForDestination(dest); |
63 | 0 | auto provider = GetSolvingProvider(scriptPubKey); |
64 | 0 | auto descriptor = InferDescriptor(scriptPubKey, *provider); |
65 | |
|
66 | 0 | const UniValue& result = signer.DisplayAddress(descriptor->ToString()); |
67 | |
|
68 | 0 | const UniValue& error = result.find_value("error"); |
69 | 0 | if (error.isStr()) return util::Error{strprintf(_("Signer returned error: %s"), error.getValStr())}; Branch (69:9): [True: 0, False: 0]
|
70 | | |
71 | 0 | const UniValue& ret_address = result.find_value("address"); |
72 | 0 | if (!ret_address.isStr()) return util::Error{_("Signer did not echo address")}; Branch (72:9): [True: 0, False: 0]
|
73 | | |
74 | 0 | if (ret_address.getValStr() != EncodeDestination(dest)) { Branch (74:9): [True: 0, False: 0]
|
75 | 0 | return util::Error{strprintf(_("Signer echoed unexpected address %s"), ret_address.getValStr())}; |
76 | 0 | } |
77 | | |
78 | 0 | return util::Result<void>(); |
79 | 0 | } |
80 | | |
81 | | // If sign is true, transaction must previously have been filled |
82 | | std::optional<PSBTError> ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, std::optional<int> sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const |
83 | 0 | { |
84 | 0 | if (!sign) { Branch (84:9): [True: 0, False: 0]
|
85 | 0 | return DescriptorScriptPubKeyMan::FillPSBT(psbt, txdata, sighash_type, false, bip32derivs, n_signed, finalize); |
86 | 0 | } |
87 | | |
88 | | // Already complete if every input is now signed |
89 | 0 | bool complete = true; |
90 | 0 | for (const auto& input : psbt.inputs) { Branch (90:28): [True: 0, False: 0]
|
91 | | // TODO: for multisig wallets, we should only care if all _our_ inputs are signed |
92 | 0 | complete &= PSBTInputSigned(input); |
93 | 0 | } |
94 | 0 | if (complete) return {}; Branch (94:9): [True: 0, False: 0]
|
95 | | |
96 | 0 | std::string strFailReason; |
97 | 0 | if(!GetExternalSigner().SignTransaction(psbt, strFailReason)) { Branch (97:8): [True: 0, False: 0]
|
98 | 0 | tfm::format(std::cerr, "Failed to sign: %s\n", strFailReason); |
99 | 0 | return PSBTError::EXTERNAL_SIGNER_FAILED; |
100 | 0 | } |
101 | 0 | if (finalize) FinalizePSBT(psbt); // This won't work in a multisig setup Branch (101:9): [True: 0, False: 0]
|
102 | 0 | return {}; |
103 | 0 | } |
104 | | } // namespace wallet |