outputtype.cpp raw

   1  // Copyright (c) 2009-2010 Satoshi Nakamoto
   2  // Copyright (c) 2009-2022 The Limenka developers
   3  // Distributed under the MIT software license, see the accompanying
   4  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   5  
   6  #include <outputtype.h>
   7  
   8  #include <pubkey.h>
   9  #include <script/script.h>
  10  #include <script/sign.h>
  11  #include <script/signingprovider.h>
  12  #include <util/vector.h>
  13  
  14  #include <assert.h>
  15  #include <optional>
  16  #include <string>
  17  
  18  static const std::string OUTPUT_TYPE_STRING_LEGACY = "legacy";
  19  static const std::string OUTPUT_TYPE_STRING_P2SH_SEGWIT = "p2sh-segwit";
  20  static const std::string OUTPUT_TYPE_STRING_BECH32 = "bech32";
  21  static const std::string OUTPUT_TYPE_STRING_BECH32M = "bech32m";
  22  static const std::string OUTPUT_TYPE_STRING_P2SPKH = "p2spkh";
  23  static const std::string OUTPUT_TYPE_STRING_UNKNOWN = "unknown";
  24  
  25  std::optional<OutputType> ParseOutputType(const std::string& type)
  26  {
  27      if (type == OUTPUT_TYPE_STRING_LEGACY) {
  28          return OutputType::LEGACY;
  29      } else if (type == OUTPUT_TYPE_STRING_P2SH_SEGWIT) {
  30          return OutputType::P2SH_SEGWIT;
  31      } else if (type == OUTPUT_TYPE_STRING_BECH32) {
  32          return OutputType::BECH32;
  33      } else if (type == OUTPUT_TYPE_STRING_BECH32M) {
  34          return OutputType::BECH32M;
  35      } else if (type == OUTPUT_TYPE_STRING_P2SPKH) {
  36          return OutputType::P2SPKH;
  37      }
  38      return std::nullopt;
  39  }
  40  
  41  const std::string& FormatOutputType(OutputType type)
  42  {
  43      switch (type) {
  44      case OutputType::LEGACY: return OUTPUT_TYPE_STRING_LEGACY;
  45      case OutputType::P2SH_SEGWIT: return OUTPUT_TYPE_STRING_P2SH_SEGWIT;
  46      case OutputType::BECH32: return OUTPUT_TYPE_STRING_BECH32;
  47      case OutputType::BECH32M: return OUTPUT_TYPE_STRING_BECH32M;
  48      case OutputType::P2SPKH: return OUTPUT_TYPE_STRING_P2SPKH;
  49      case OutputType::UNKNOWN: return OUTPUT_TYPE_STRING_UNKNOWN;
  50      } // no default case, so the compiler can warn about missing cases
  51      assert(false);
  52  }
  53  
  54  CTxDestination GetDestinationForKey(const CPubKey& key, OutputType type)
  55  {
  56      switch (type) {
  57      case OutputType::LEGACY: return PKHash(key);
  58      case OutputType::P2SH_SEGWIT:
  59      case OutputType::BECH32: {
  60          if (!key.IsCompressed()) return PKHash(key);
  61          CTxDestination witdest = WitnessV0KeyHash(key);
  62          CScript witprog = GetScriptForDestination(witdest);
  63          if (type == OutputType::P2SH_SEGWIT) {
  64              return ScriptHash(witprog);
  65          } else {
  66              return witdest;
  67          }
  68      }
  69      case OutputType::BECH32M:
  70      case OutputType::UNKNOWN: {} // This function should never be used with BECH32M or UNKNOWN, so let it assert
  71      } // no default case, so the compiler can warn about missing cases
  72      assert(false);
  73  }
  74  
  75  std::vector<CTxDestination> GetAllDestinationsForKey(const CPubKey& key)
  76  {
  77      PKHash keyid(key);
  78      CTxDestination p2pkh{keyid};
  79      if (key.IsCompressed() && g_implicit_segwit) {
  80          CTxDestination segwit = WitnessV0KeyHash(keyid);
  81          CTxDestination p2sh = ScriptHash(GetScriptForDestination(segwit));
  82          return Vector(std::move(p2pkh), std::move(p2sh), std::move(segwit));
  83      } else {
  84          return Vector(std::move(p2pkh));
  85      }
  86  }
  87  
  88  CTxDestination AddAndGetDestinationForScript(FlatSigningProvider& keystore, const CScript& script, OutputType type)
  89  {
  90      // Add script to keystore
  91      keystore.scripts.emplace(CScriptID(script), script);
  92  
  93      switch (type) {
  94      case OutputType::LEGACY:
  95          return ScriptHash(script);
  96      case OutputType::P2SH_SEGWIT:
  97      case OutputType::BECH32: {
  98          CTxDestination witdest = WitnessV0ScriptHash(script);
  99          CScript witprog = GetScriptForDestination(witdest);
 100          // Add the redeemscript, so that P2WSH and P2SH-P2WSH outputs are recognized as ours.
 101          keystore.scripts.emplace(CScriptID(witprog), witprog);
 102          if (type == OutputType::BECH32) {
 103              return witdest;
 104          } else {
 105              return ScriptHash(witprog);
 106          }
 107      }
 108      case OutputType::BECH32M:
 109      case OutputType::P2SPKH:
 110      case OutputType::UNKNOWN: {} // This function should not be used for BECH32M, P2SPKH, or UNKNOWN, so let it assert
 111      } // no default case, so the compiler can warn about missing cases
 112      assert(false);
 113  }
 114  
 115  std::optional<OutputType> OutputTypeFromDestination(const CTxDestination& dest) {
 116      if (std::holds_alternative<PKHash>(dest) ||
 117          std::holds_alternative<ScriptHash>(dest)) {
 118          return OutputType::LEGACY;
 119      }
 120      if (std::holds_alternative<WitnessV0KeyHash>(dest) ||
 121          std::holds_alternative<WitnessV0ScriptHash>(dest)) {
 122          return OutputType::BECH32;
 123      }
 124      if (std::holds_alternative<WitnessV1Taproot>(dest) ||
 125          std::holds_alternative<WitnessUnknown>(dest)) {
 126          return OutputType::BECH32M;
 127      }
 128      if (std::holds_alternative<WitnessV3SpkHash>(dest)) {
 129          return OutputType::P2SPKH;
 130      }
 131      return std::nullopt;
 132  }
 133