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