// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2022 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 <outputtype.h> #include <pubkey.h> #include <script/script.h> #include <script/sign.h> #include <script/signingprovider.h> #include <script/standard.h> #include <util/vector.h> #include <assert.h> #include <optional> #include <string> static const std::string OUTPUT_TYPE_STRING_LEGACY = "legacy"; static const std::string OUTPUT_TYPE_STRING_P2SH_SEGWIT = "p2sh-segwit"; static const std::string OUTPUT_TYPE_STRING_BECH32 = "bech32"; static const std::string OUTPUT_TYPE_STRING_BECH32M = "bech32m"; static const std::string OUTPUT_TYPE_STRING_UNKNOWN = "unknown"; std::optional<OutputType> ParseOutputType(const std::string& type) { if (type == OUTPUT_TYPE_STRING_LEGACY) { return OutputType::LEGACY; } else if (type == OUTPUT_TYPE_STRING_P2SH_SEGWIT) { return OutputType::P2SH_SEGWIT; } else if (type == OUTPUT_TYPE_STRING_BECH32) { return OutputType::BECH32; } else if (type == OUTPUT_TYPE_STRING_BECH32M) { return OutputType::BECH32M; } else if (type == OUTPUT_TYPE_STRING_UNKNOWN) { return OutputType::UNKNOWN; } return std::nullopt; } const std::string& FormatOutputType(OutputType type) { switch (type) { case OutputType::LEGACY: return OUTPUT_TYPE_STRING_LEGACY; case OutputType::P2SH_SEGWIT: return OUTPUT_TYPE_STRING_P2SH_SEGWIT; case OutputType::BECH32: return OUTPUT_TYPE_STRING_BECH32; case OutputType::BECH32M: return OUTPUT_TYPE_STRING_BECH32M; case OutputType::UNKNOWN: return OUTPUT_TYPE_STRING_UNKNOWN; } // no default case, so the compiler can warn about missing cases assert(false); } CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type) { switch (type) { case OutputType::LEGACY: return PKHash(key); case OutputType::P2SH_SEGWIT: case OutputType::BECH32: { if (!key.IsCompressed()) return PKHash(key); CTxDestination witdest = WitnessV0KeyHash(key); CScript witprog = GetScriptForDestination(witdest); if (type == OutputType::P2SH_SEGWIT) { return ScriptHash(witprog); } else { return witdest; } } case OutputType::BECH32M: case OutputType::UNKNOWN: {} // This function should never be used with BECH32M or UNKNOWN, so let it assert } // no default case, so the compiler can warn about missing cases assert(false); } std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key) { PKHash keyid(key); CTxDestination p2pkh{keyid}; if (key.IsCompressed()) { CTxDestination segwit = WitnessV0KeyHash(keyid); CTxDestination p2sh = ScriptHash(GetScriptForDestination(segwit)); return Vector(std::move(p2pkh), std::move(p2sh), std::move(segwit)); } else { return Vector(std::move(p2pkh)); } } CTxDestination AddAndGetDestinationForScript(FillableSigningProvider& keystore, const CScript& script, OutputType type) { // Add script to keystore keystore.AddCScript(script); // Note that scripts over 520 bytes are not yet supported. switch (type) { case OutputType::LEGACY: return ScriptHash(script); case OutputType::P2SH_SEGWIT: case OutputType::BECH32: { CTxDestination witdest = WitnessV0ScriptHash(script); CScript witprog = GetScriptForDestination(witdest); // Add the redeemscript, so that P2WSH and P2SH-P2WSH outputs are recognized as ours. keystore.AddCScript(witprog); if (type == OutputType::BECH32) { return witdest; } else { return ScriptHash(witprog); } } case OutputType::BECH32M: case OutputType::UNKNOWN: {} // This function should not be used for BECH32M or UNKNOWN, so let it assert } // no default case, so the compiler can warn about missing cases assert(false); } std::optional<OutputType> OutputTypeFromDestination(const CTxDestination& dest) { if (std::holds_alternative<PKHash>(dest) || std::holds_alternative<ScriptHash>(dest)) { return OutputType::LEGACY; } if (std::holds_alternative<WitnessV0KeyHash>(dest) || std::holds_alternative<WitnessV0ScriptHash>(dest)) { return OutputType::BECH32; } if (std::holds_alternative<WitnessV1Taproot>(dest) || std::holds_alternative<WitnessUnknown>(dest)) { return OutputType::BECH32M; } return std::nullopt; }