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