/
githubmirror
/
bitcoin
Обзор
Документация
Войти
/
githubmirror
/
bitcoin
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
v31.0
src/external_signer.cpp
125 строк
5 KB
MarcoFalke
util: Remove brittle and confusing sp::Popen(std::string)
17 фев 2026, 14:55
17 фев 2026, 14:55
fa626bd
Код
Авторство
О чём код?
// Copyright (c) 2018-present 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 <external_signer.h> #include <chainparams.h> #include <common/run_command.h> #include <core_io.h> #include <psbt.h> #include <util/strencodings.h> #include <util/subprocess.h> #include <algorithm> #include <stdexcept> #include <string> #include <vector> ExternalSigner::ExternalSigner(std::vector<std::string> command, std::string chain, std::string fingerprint, std::string name) : m_command{std::move(command)}, m_chain{std::move(chain)}, m_fingerprint{std::move(fingerprint)}, m_name{std::move(name)} {} std::vector<std::string> ExternalSigner::NetworkArg() const { return {"--chain", m_chain}; } bool ExternalSigner::Enumerate(const std::string& command, std::vector<ExternalSigner>& signers, const std::string& chain) { // Call <command> enumerate std::vector<std::string> cmd_args = Cat(subprocess::util::split(command), {"enumerate"}); const UniValue result = RunCommandParseJSON(cmd_args, ""); if (!result.isArray()) { throw std::runtime_error(strprintf("'%s' received invalid response, expected array of signers", command)); } for (const UniValue& signer : result.getValues()) { // Check for error const UniValue& error = signer.find_value("error"); if (!error.isNull()) { if (!error.isStr()) { throw std::runtime_error(strprintf("'%s' error", command)); } throw std::runtime_error(strprintf("'%s' error: %s", command, error.getValStr())); } // Check if fingerprint is present const UniValue& fingerprint = signer.find_value("fingerprint"); if (fingerprint.isNull()) { throw std::runtime_error(strprintf("'%s' received invalid response, missing signer fingerprint", command)); } const std::string& fingerprintStr{fingerprint.get_str()}; // Skip duplicate signer bool duplicate = false; for (const ExternalSigner& signer : signers) { if (signer.m_fingerprint.compare(fingerprintStr) == 0) duplicate = true; } if (duplicate) break; std::string name; const UniValue& model_field = signer.find_value("model"); if (model_field.isStr() && model_field.getValStr() != "") { name += model_field.getValStr(); } signers.emplace_back(subprocess::util::split(command), chain, fingerprintStr, name); } return true; } UniValue ExternalSigner::DisplayAddress(const std::string& descriptor) const { return RunCommandParseJSON(Cat(m_command, Cat(Cat({"--fingerprint", m_fingerprint}, NetworkArg()), {"displayaddress", "--desc", descriptor})), ""); } UniValue ExternalSigner::GetDescriptors(const int account) { return RunCommandParseJSON(Cat(m_command, Cat(Cat({"--fingerprint", m_fingerprint}, NetworkArg()), {"getdescriptors", "--account", strprintf("%d", account)})), ""); } bool ExternalSigner::SignTransaction(PartiallySignedTransaction& psbtx, std::string& error) { // Serialize the PSBT DataStream ssTx{}; ssTx << psbtx; // parse ExternalSigner master fingerprint std::vector<unsigned char> parsed_m_fingerprint = ParseHex(m_fingerprint); // Check if signer fingerprint matches any input master key fingerprint auto matches_signer_fingerprint = [&](const PSBTInput& input) { for (const auto& entry : input.hd_keypaths) { if (std::ranges::equal(parsed_m_fingerprint, entry.second.fingerprint)) return true; } for (const auto& entry : input.m_tap_bip32_paths) { if (std::ranges::equal(parsed_m_fingerprint, entry.second.second.fingerprint)) return true; } return false; }; if (!std::any_of(psbtx.inputs.begin(), psbtx.inputs.end(), matches_signer_fingerprint)) { error = "Signer fingerprint " + m_fingerprint + " does not match any of the inputs:\n" + EncodeBase64(ssTx.str()); return false; } const std::vector<std::string> command = Cat(m_command, Cat({"--stdin", "--fingerprint", m_fingerprint}, NetworkArg())); const std::string stdinStr = "signtx " + EncodeBase64(ssTx.str()); const UniValue signer_result = RunCommandParseJSON(command, stdinStr); if (signer_result.find_value("error").isStr()) { error = signer_result.find_value("error").get_str(); return false; } if (!signer_result.find_value("psbt").isStr()) { error = "Unexpected result from signer"; return false; } PartiallySignedTransaction signer_psbtx; std::string signer_psbt_error; if (!DecodeBase64PSBT(signer_psbtx, signer_result.find_value("psbt").get_str(), signer_psbt_error)) { error = strprintf("TX decode failed %s", signer_psbt_error); return false; } psbtx = signer_psbtx; return true; }