addresstype.cpp raw

   1  // Copyright (c) 2023 The Limenka developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or https://www.opensource.org/licenses/mit-license.php.
   4  
   5  #include <addresstype.h>
   6  
   7  #include <crypto/sha256.h>
   8  #include <hash.h>
   9  #include <pubkey.h>
  10  #include <script/script.h>
  11  #include <script/solver.h>
  12  #include <uint256.h>
  13  #include <util/hash_type.h>
  14  
  15  #include <cassert>
  16  #include <vector>
  17  
  18  typedef std::vector<unsigned char> valtype;
  19  
  20  ScriptHash::ScriptHash(const CScript& in) : BaseHash(Hash160(in)) {}
  21  ScriptHash::ScriptHash(const CScriptID& in) : BaseHash{in} {}
  22  
  23  PKHash::PKHash(const CPubKey& pubkey) : BaseHash(pubkey.GetID()) {}
  24  PKHash::PKHash(const CKeyID& pubkey_id) : BaseHash(pubkey_id) {}
  25  
  26  WitnessV0KeyHash::WitnessV0KeyHash(const CPubKey& pubkey) : BaseHash(pubkey.GetID()) {}
  27  WitnessV0KeyHash::WitnessV0KeyHash(const PKHash& pubkey_hash) : BaseHash{pubkey_hash} {}
  28  
  29  CKeyID ToKeyID(const PKHash& key_hash)
  30  {
  31      return CKeyID{uint160{key_hash}};
  32  }
  33  
  34  CKeyID ToKeyID(const WitnessV0KeyHash& key_hash)
  35  {
  36      return CKeyID{uint160{key_hash}};
  37  }
  38  
  39  CScriptID ToScriptID(const ScriptHash& script_hash)
  40  {
  41      return CScriptID{uint160{script_hash}};
  42  }
  43  
  44  WitnessV3SpkHash::WitnessV3SpkHash(const XOnlyPubKey& xpk)
  45  {
  46      uint256 tmp;
  47      CSHA256().Write(xpk.data(), xpk.size()).Finalize(tmp.begin());
  48      CSHA256().Write(tmp.begin(), 32).Finalize(begin());
  49  }
  50  
  51  WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in)
  52  {
  53      CSHA256().Write(in.data(), in.size()).Finalize(begin());
  54  }
  55  
  56  bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
  57  {
  58      std::vector<valtype> vSolutions;
  59      TxoutType whichType = Solver(scriptPubKey, vSolutions);
  60  
  61      switch (whichType) {
  62      case TxoutType::PUBKEY: {
  63          CPubKey pubKey(vSolutions[0]);
  64          if (!pubKey.IsValid()) {
  65              addressRet = CNoDestination(scriptPubKey);
  66          } else {
  67              addressRet = PubKeyDestination(pubKey);
  68          }
  69          return false;
  70      }
  71      case TxoutType::PUBKEYHASH: {
  72          addressRet = PKHash(uint160(vSolutions[0]));
  73          return true;
  74      }
  75      case TxoutType::SCRIPTHASH: {
  76          addressRet = ScriptHash(uint160(vSolutions[0]));
  77          return true;
  78      }
  79      case TxoutType::WITNESS_V0_KEYHASH: {
  80          WitnessV0KeyHash hash;
  81          std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
  82          addressRet = hash;
  83          return true;
  84      }
  85      case TxoutType::WITNESS_V0_SCRIPTHASH: {
  86          WitnessV0ScriptHash hash;
  87          std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
  88          addressRet = hash;
  89          return true;
  90      }
  91      case TxoutType::WITNESS_V1_TAPROOT: {
  92          WitnessV1Taproot tap;
  93          std::copy(vSolutions[0].begin(), vSolutions[0].end(), tap.begin());
  94          addressRet = tap;
  95          return true;
  96      }
  97      case TxoutType::WITNESS_V3_SPKHASH: {
  98          WitnessV3SpkHash hash;
  99          std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
 100          addressRet = hash;
 101          return true;
 102      }
 103      case TxoutType::ANCHOR: {
 104          addressRet = PayToAnchor();
 105          return true;
 106      }
 107      case TxoutType::WITNESS_UNKNOWN: {
 108          addressRet = WitnessUnknown{vSolutions[0][0], vSolutions[1]};
 109          return true;
 110      }
 111      case TxoutType::MULTISIG:
 112      case TxoutType::NULL_DATA:
 113      case TxoutType::NONSTANDARD:
 114      case TxoutType::WITNESS_V4_BPCT:
 115          addressRet = CNoDestination(scriptPubKey);
 116          return false;
 117      } // no default case, so the compiler can warn about missing cases
 118      assert(false);
 119  }
 120  
 121  namespace {
 122  class CScriptVisitor
 123  {
 124  public:
 125      CScript operator()(const CNoDestination& dest) const
 126      {
 127          return dest.GetScript();
 128      }
 129  
 130      CScript operator()(const PubKeyDestination& dest) const
 131      {
 132          return CScript() << ToByteVector(dest.GetPubKey()) << OP_CHECKSIG;
 133      }
 134  
 135      CScript operator()(const PKHash& keyID) const
 136      {
 137          return CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
 138      }
 139  
 140      CScript operator()(const ScriptHash& scriptID) const
 141      {
 142          return CScript() << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
 143      }
 144  
 145      CScript operator()(const WitnessV0KeyHash& id) const
 146      {
 147          return CScript() << OP_0 << ToByteVector(id);
 148      }
 149  
 150      CScript operator()(const WitnessV0ScriptHash& id) const
 151      {
 152          return CScript() << OP_0 << ToByteVector(id);
 153      }
 154  
 155      CScript operator()(const WitnessV1Taproot& tap) const
 156      {
 157          return CScript() << OP_1 << ToByteVector(tap);
 158      }
 159  
 160      CScript operator()(const WitnessV3SpkHash& id) const
 161      {
 162          return CScript() << OP_3 << ToByteVector(id);
 163      }
 164  
 165      CScript operator()(const WitnessUnknown& id) const
 166      {
 167          return CScript() << CScript::EncodeOP_N(id.GetWitnessVersion()) << id.GetWitnessProgram();
 168      }
 169  
 170      // Stealth addresses commit per-payment; no fixed script.
 171      CScript operator()(const WitnessV4StealthAddress& id) const { return {}; }
 172  };
 173  
 174  class ValidDestinationVisitor
 175  {
 176  public:
 177      bool operator()(const CNoDestination& dest) const { return false; }
 178      bool operator()(const PubKeyDestination& dest) const { return false; }
 179      bool operator()(const PKHash& dest) const { return true; }
 180      bool operator()(const ScriptHash& dest) const { return true; }
 181      bool operator()(const WitnessV0KeyHash& dest) const { return true; }
 182      bool operator()(const WitnessV0ScriptHash& dest) const { return true; }
 183      bool operator()(const WitnessV1Taproot& dest) const { return true; }
 184      bool operator()(const WitnessV3SpkHash& dest) const { return true; }
 185      bool operator()(const WitnessV4StealthAddress& dest) const
 186      {
 187          return dest.view.IsFullyValid() && dest.spend.IsFullyValid();
 188      }
 189      bool operator()(const WitnessUnknown& dest) const { return true; }
 190  };
 191  } // namespace
 192  
 193  CScript GetScriptForDestination(const CTxDestination& dest)
 194  {
 195      return std::visit(CScriptVisitor(), dest);
 196  }
 197  
 198  bool IsValidDestination(const CTxDestination& dest) {
 199      return std::visit(ValidDestinationVisitor(), dest);
 200  }
 201