Skip to content

Commit 7a172c7

Browse files
committed
Move CTxDestination to its own file
CTxDestination is really our internal representation of an address and doesn't really have anything to do with standard script types, so move them to their own file.
1 parent 145f36e commit 7a172c7

21 files changed

+291
-247
lines changed

src/Makefile.am

+2
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ endif
117117
.PHONY: FORCE check-symbols check-security
118118
# bitcoin core #
119119
BITCOIN_CORE_H = \
120+
addresstype.h \
120121
addrdb.h \
121122
addrman.h \
122123
addrman_impl.h \
@@ -657,6 +658,7 @@ libbitcoin_consensus_a_SOURCES = \
657658
libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS)
658659
libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
659660
libbitcoin_common_a_SOURCES = \
661+
addresstype.cpp \
660662
base58.cpp \
661663
bech32.cpp \
662664
chainparams.cpp \

src/addresstype.cpp

+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// Copyright (c) 2023 The Bitcoin Core 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+
#include <script/script.h>
7+
#include <script/standard.h>
8+
#include <hash.h>
9+
#include <pubkey.h>
10+
#include <uint256.h>
11+
#include <util/hash_type.h>
12+
13+
#include <vector>
14+
15+
typedef std::vector<unsigned char> valtype;
16+
17+
ScriptHash::ScriptHash(const CScript& in) : BaseHash(Hash160(in)) {}
18+
ScriptHash::ScriptHash(const CScriptID& in) : BaseHash(static_cast<uint160>(in)) {}
19+
20+
PKHash::PKHash(const CPubKey& pubkey) : BaseHash(pubkey.GetID()) {}
21+
PKHash::PKHash(const CKeyID& pubkey_id) : BaseHash(pubkey_id) {}
22+
23+
WitnessV0KeyHash::WitnessV0KeyHash(const CPubKey& pubkey) : BaseHash(pubkey.GetID()) {}
24+
WitnessV0KeyHash::WitnessV0KeyHash(const PKHash& pubkey_hash) : BaseHash(static_cast<uint160>(pubkey_hash)) {}
25+
26+
CKeyID ToKeyID(const PKHash& key_hash)
27+
{
28+
return CKeyID{static_cast<uint160>(key_hash)};
29+
}
30+
31+
CKeyID ToKeyID(const WitnessV0KeyHash& key_hash)
32+
{
33+
return CKeyID{static_cast<uint160>(key_hash)};
34+
}
35+
36+
CScriptID ToScriptID(const ScriptHash& script_hash)
37+
{
38+
return CScriptID{static_cast<uint160>(script_hash)};
39+
}
40+
41+
WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in)
42+
{
43+
CSHA256().Write(in.data(), in.size()).Finalize(begin());
44+
}
45+
46+
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
47+
{
48+
std::vector<valtype> vSolutions;
49+
TxoutType whichType = Solver(scriptPubKey, vSolutions);
50+
51+
switch (whichType) {
52+
case TxoutType::PUBKEY: {
53+
CPubKey pubKey(vSolutions[0]);
54+
if (!pubKey.IsValid())
55+
return false;
56+
57+
addressRet = PKHash(pubKey);
58+
return true;
59+
}
60+
case TxoutType::PUBKEYHASH: {
61+
addressRet = PKHash(uint160(vSolutions[0]));
62+
return true;
63+
}
64+
case TxoutType::SCRIPTHASH: {
65+
addressRet = ScriptHash(uint160(vSolutions[0]));
66+
return true;
67+
}
68+
case TxoutType::WITNESS_V0_KEYHASH: {
69+
WitnessV0KeyHash hash;
70+
std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
71+
addressRet = hash;
72+
return true;
73+
}
74+
case TxoutType::WITNESS_V0_SCRIPTHASH: {
75+
WitnessV0ScriptHash hash;
76+
std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
77+
addressRet = hash;
78+
return true;
79+
}
80+
case TxoutType::WITNESS_V1_TAPROOT: {
81+
WitnessV1Taproot tap;
82+
std::copy(vSolutions[0].begin(), vSolutions[0].end(), tap.begin());
83+
addressRet = tap;
84+
return true;
85+
}
86+
case TxoutType::WITNESS_UNKNOWN: {
87+
WitnessUnknown unk;
88+
unk.version = vSolutions[0][0];
89+
std::copy(vSolutions[1].begin(), vSolutions[1].end(), unk.program);
90+
unk.length = vSolutions[1].size();
91+
addressRet = unk;
92+
return true;
93+
}
94+
case TxoutType::MULTISIG:
95+
case TxoutType::NULL_DATA:
96+
case TxoutType::NONSTANDARD:
97+
return false;
98+
} // no default case, so the compiler can warn about missing cases
99+
assert(false);
100+
}
101+
102+
namespace {
103+
class CScriptVisitor
104+
{
105+
public:
106+
CScript operator()(const CNoDestination& dest) const
107+
{
108+
return CScript();
109+
}
110+
111+
CScript operator()(const PKHash& keyID) const
112+
{
113+
return CScript() << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
114+
}
115+
116+
CScript operator()(const ScriptHash& scriptID) const
117+
{
118+
return CScript() << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
119+
}
120+
121+
CScript operator()(const WitnessV0KeyHash& id) const
122+
{
123+
return CScript() << OP_0 << ToByteVector(id);
124+
}
125+
126+
CScript operator()(const WitnessV0ScriptHash& id) const
127+
{
128+
return CScript() << OP_0 << ToByteVector(id);
129+
}
130+
131+
CScript operator()(const WitnessV1Taproot& tap) const
132+
{
133+
return CScript() << OP_1 << ToByteVector(tap);
134+
}
135+
136+
CScript operator()(const WitnessUnknown& id) const
137+
{
138+
return CScript() << CScript::EncodeOP_N(id.version) << std::vector<unsigned char>(id.program, id.program + id.length);
139+
}
140+
};
141+
} // namespace
142+
143+
CScript GetScriptForDestination(const CTxDestination& dest)
144+
{
145+
return std::visit(CScriptVisitor(), dest);
146+
}
147+
148+
bool IsValidDestination(const CTxDestination& dest) {
149+
return dest.index() != 0;
150+
}

src/addresstype.h

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// Copyright (c) 2023 The Bitcoin Core 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+
#ifndef BITCOIN_ADDRESSTYPE_H
6+
#define BITCOIN_ADDRESSTYPE_H
7+
8+
#include <pubkey.h>
9+
#include <script/script.h>
10+
#include <uint256.h>
11+
#include <util/hash_type.h>
12+
13+
#include <variant>
14+
#include <algorithm>
15+
16+
class CNoDestination {
17+
public:
18+
friend bool operator==(const CNoDestination &a, const CNoDestination &b) { return true; }
19+
friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; }
20+
};
21+
22+
struct PKHash : public BaseHash<uint160>
23+
{
24+
PKHash() : BaseHash() {}
25+
explicit PKHash(const uint160& hash) : BaseHash(hash) {}
26+
explicit PKHash(const CPubKey& pubkey);
27+
explicit PKHash(const CKeyID& pubkey_id);
28+
};
29+
CKeyID ToKeyID(const PKHash& key_hash);
30+
31+
struct WitnessV0KeyHash;
32+
33+
struct ScriptHash : public BaseHash<uint160>
34+
{
35+
ScriptHash() : BaseHash() {}
36+
// These don't do what you'd expect.
37+
// Use ScriptHash(GetScriptForDestination(...)) instead.
38+
explicit ScriptHash(const WitnessV0KeyHash& hash) = delete;
39+
explicit ScriptHash(const PKHash& hash) = delete;
40+
41+
explicit ScriptHash(const uint160& hash) : BaseHash(hash) {}
42+
explicit ScriptHash(const CScript& script);
43+
explicit ScriptHash(const CScriptID& script);
44+
};
45+
CScriptID ToScriptID(const ScriptHash& script_hash);
46+
47+
struct WitnessV0ScriptHash : public BaseHash<uint256>
48+
{
49+
WitnessV0ScriptHash() : BaseHash() {}
50+
explicit WitnessV0ScriptHash(const uint256& hash) : BaseHash(hash) {}
51+
explicit WitnessV0ScriptHash(const CScript& script);
52+
};
53+
54+
struct WitnessV0KeyHash : public BaseHash<uint160>
55+
{
56+
WitnessV0KeyHash() : BaseHash() {}
57+
explicit WitnessV0KeyHash(const uint160& hash) : BaseHash(hash) {}
58+
explicit WitnessV0KeyHash(const CPubKey& pubkey);
59+
explicit WitnessV0KeyHash(const PKHash& pubkey_hash);
60+
};
61+
CKeyID ToKeyID(const WitnessV0KeyHash& key_hash);
62+
63+
struct WitnessV1Taproot : public XOnlyPubKey
64+
{
65+
WitnessV1Taproot() : XOnlyPubKey() {}
66+
explicit WitnessV1Taproot(const XOnlyPubKey& xpk) : XOnlyPubKey(xpk) {}
67+
};
68+
69+
//! CTxDestination subtype to encode any future Witness version
70+
struct WitnessUnknown
71+
{
72+
unsigned int version;
73+
unsigned int length;
74+
unsigned char program[40];
75+
76+
friend bool operator==(const WitnessUnknown& w1, const WitnessUnknown& w2) {
77+
if (w1.version != w2.version) return false;
78+
if (w1.length != w2.length) return false;
79+
return std::equal(w1.program, w1.program + w1.length, w2.program);
80+
}
81+
82+
friend bool operator<(const WitnessUnknown& w1, const WitnessUnknown& w2) {
83+
if (w1.version < w2.version) return true;
84+
if (w1.version > w2.version) return false;
85+
if (w1.length < w2.length) return true;
86+
if (w1.length > w2.length) return false;
87+
return std::lexicographical_compare(w1.program, w1.program + w1.length, w2.program, w2.program + w2.length);
88+
}
89+
};
90+
91+
/**
92+
* A txout script template with a specific destination. It is either:
93+
* * CNoDestination: no destination set
94+
* * PKHash: TxoutType::PUBKEYHASH destination (P2PKH)
95+
* * ScriptHash: TxoutType::SCRIPTHASH destination (P2SH)
96+
* * WitnessV0ScriptHash: TxoutType::WITNESS_V0_SCRIPTHASH destination (P2WSH)
97+
* * WitnessV0KeyHash: TxoutType::WITNESS_V0_KEYHASH destination (P2WPKH)
98+
* * WitnessV1Taproot: TxoutType::WITNESS_V1_TAPROOT destination (P2TR)
99+
* * WitnessUnknown: TxoutType::WITNESS_UNKNOWN destination (P2W???)
100+
* A CTxDestination is the internal data type encoded in a bitcoin address
101+
*/
102+
using CTxDestination = std::variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown>;
103+
104+
/** Check whether a CTxDestination is a CNoDestination. */
105+
bool IsValidDestination(const CTxDestination& dest);
106+
107+
/**
108+
* Parse a standard scriptPubKey for the destination address. Assigns result to
109+
* the addressRet parameter and returns true if successful. Currently only works for P2PK,
110+
* P2PKH, P2SH, P2WPKH, and P2WSH scripts.
111+
*/
112+
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
113+
114+
/**
115+
* Generate a Bitcoin scriptPubKey for the given CTxDestination. Returns a P2PKH
116+
* script for a CKeyID destination, a P2SH script for a CScriptID, and an empty
117+
* script for CNoDestination.
118+
*/
119+
CScript GetScriptForDestination(const CTxDestination& dest);
120+
121+
#endif // BITCOIN_ADDRESSTYPE_H

src/bench/descriptors.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
#include <key.h>
77
#include <pubkey.h>
88
#include <script/descriptor.h>
9-
#include <script/standard.h>
109

1110
#include <string>
1211
#include <utility>

src/interfaces/wallet.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
#ifndef BITCOIN_INTERFACES_WALLET_H
66
#define BITCOIN_INTERFACES_WALLET_H
77

8+
#include <addresstype.h>
89
#include <consensus/amount.h>
9-
#include <interfaces/chain.h> // For ChainClient
10-
#include <pubkey.h> // For CKeyID and CScriptID (definitions needed in CTxDestination instantiation)
10+
#include <interfaces/chain.h>
11+
#include <pubkey.h>
1112
#include <script/script.h>
12-
#include <script/standard.h> // For CTxDestination
13-
#include <support/allocators/secure.h> // For SecureString
13+
#include <support/allocators/secure.h>
1414
#include <util/fs.h>
1515
#include <util/message.h>
1616
#include <util/result.h>

src/key_io.h

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#ifndef BITCOIN_KEY_IO_H
77
#define BITCOIN_KEY_IO_H
88

9+
#include <addresstype.h>
910
#include <chainparams.h>
1011
#include <key.h>
1112
#include <pubkey.h>

src/outputtype.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
#ifndef BITCOIN_OUTPUTTYPE_H
77
#define BITCOIN_OUTPUTTYPE_H
88

9+
#include <addresstype.h>
910
#include <script/signingprovider.h>
10-
#include <script/standard.h>
1111

1212
#include <array>
1313
#include <optional>

src/script/signingprovider.h

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#ifndef BITCOIN_SCRIPT_SIGNINGPROVIDER_H
77
#define BITCOIN_SCRIPT_SIGNINGPROVIDER_H
88

9+
#include <addresstype.h>
910
#include <attributes.h>
1011
#include <key.h>
1112
#include <pubkey.h>

0 commit comments

Comments
 (0)