Line data Source code
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 <wallet/external_signer_scriptpubkeyman.h> 10 : 11 : #include <iostream> 12 : #include <memory> 13 : #include <stdexcept> 14 : #include <string> 15 : #include <utility> 16 : #include <vector> 17 2 : 18 2 : namespace wallet { 19 0 : bool ExternalSignerScriptPubKeyMan::SetupDescriptor(std::unique_ptr<Descriptor> desc) 20 : { 21 0 : LOCK(cs_desc_man); 22 0 : assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)); 23 0 : assert(m_storage.IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)); 24 : 25 0 : int64_t creation_time = GetTime(); 26 : 27 2 : // Make the descriptor 28 0 : WalletDescriptor w_desc(std::move(desc), creation_time, 0, 0, 0); 29 0 : m_wallet_descriptor = w_desc; 30 : 31 : // Store the descriptor 32 0 : WalletBatch batch(m_storage.GetDatabase()); 33 0 : if (!batch.WriteDescriptor(GetID(), m_wallet_descriptor)) { 34 0 : throw std::runtime_error(std::string(__func__) + ": writing descriptor failed"); 35 : } 36 : 37 : // TopUp 38 0 : TopUp(); 39 : 40 0 : m_storage.UnsetBlankWalletFlag(batch); 41 : return true; 42 0 : } 43 : 44 0 : ExternalSigner ExternalSignerScriptPubKeyMan::GetExternalSigner() { 45 0 : const std::string command = gArgs.GetArg("-signer", ""); 46 0 : if (command == "") throw std::runtime_error(std::string(__func__) + ": restart bitcoind with -signer=<cmd>"); 47 0 : std::vector<ExternalSigner> signers; 48 0 : ExternalSigner::Enumerate(command, signers, Params().GetChainTypeString()); 49 0 : if (signers.empty()) throw std::runtime_error(std::string(__func__) + ": No external signers found"); 50 : // TODO: add fingerprint argument instead of failing in case of multiple signers. 51 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."); 52 0 : return signers[0]; 53 0 : } 54 : 55 0 : bool ExternalSignerScriptPubKeyMan::DisplayAddress(const CScript scriptPubKey, const ExternalSigner &signer) const 56 : { 57 : // TODO: avoid the need to infer a descriptor from inside a descriptor wallet 58 0 : auto provider = GetSolvingProvider(scriptPubKey); 59 0 : auto descriptor = InferDescriptor(scriptPubKey, *provider); 60 : 61 0 : signer.DisplayAddress(descriptor->ToString()); 62 : // TODO inspect result 63 : return true; 64 0 : } 65 : 66 : // If sign is true, transaction must previously have been filled 67 0 : TransactionError ExternalSignerScriptPubKeyMan::FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, int sighash_type, bool sign, bool bip32derivs, int* n_signed, bool finalize) const 68 : { 69 0 : if (!sign) { 70 0 : return DescriptorScriptPubKeyMan::FillPSBT(psbt, txdata, sighash_type, false, bip32derivs, n_signed, finalize); 71 : } 72 : 73 : // Already complete if every input is now signed 74 2 : bool complete = true; 75 0 : for (const auto& input : psbt.inputs) { 76 : // TODO: for multisig wallets, we should only care if all _our_ inputs are signed 77 0 : complete &= PSBTInputSigned(input); 78 : } 79 0 : if (complete) return TransactionError::OK; 80 : 81 0 : std::string strFailReason; 82 0 : if(!GetExternalSigner().SignTransaction(psbt, strFailReason)) { 83 0 : tfm::format(std::cerr, "Failed to sign: %s\n", strFailReason); 84 0 : return TransactionError::EXTERNAL_SIGNER_FAILED; 85 : } 86 0 : if (finalize) FinalizePSBT(psbt); // This won't work in a multisig setup 87 0 : return TransactionError::OK; 88 0 : } 89 : } // namespace wallet