Skip to content

Commit c091b99

Browse files
committed
Implement BIP173 addresses and tests
1 parent bd355b8 commit c091b99

19 files changed

+397
-32
lines changed

src/base58.cpp

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44

55
#include "base58.h"
66

7+
#include "bech32.h"
78
#include "hash.h"
89
#include "script/script.h"
910
#include "uint256.h"
11+
#include "utilstrencodings.h"
1012

1113
#include <boost/variant/apply_visitor.hpp>
1214
#include <boost/variant/static_visitor.hpp>
@@ -235,7 +237,31 @@ class DestinationEncoder : public boost::static_visitor<std::string>
235237
return EncodeBase58Check(data);
236238
}
237239

238-
std::string operator()(const CNoDestination& no) const { return ""; }
240+
std::string operator()(const WitnessV0KeyHash& id) const
241+
{
242+
std::vector<unsigned char> data = {0};
243+
ConvertBits<8, 5, true>(data, id.begin(), id.end());
244+
return bech32::Encode(m_params.Bech32HRP(), data);
245+
}
246+
247+
std::string operator()(const WitnessV0ScriptHash& id) const
248+
{
249+
std::vector<unsigned char> data = {0};
250+
ConvertBits<8, 5, true>(data, id.begin(), id.end());
251+
return bech32::Encode(m_params.Bech32HRP(), data);
252+
}
253+
254+
std::string operator()(const WitnessUnknown& id) const
255+
{
256+
if (id.version < 1 || id.version > 16 || id.length < 2 || id.length > 40) {
257+
return {};
258+
}
259+
std::vector<unsigned char> data = {(unsigned char)id.version};
260+
ConvertBits<8, 5, true>(data, id.program, id.program + id.length);
261+
return bech32::Encode(m_params.Bech32HRP(), data);
262+
}
263+
264+
std::string operator()(const CNoDestination& no) const { return {}; }
239265
};
240266

241267
CTxDestination DecodeDestination(const std::string& str, const CChainParams& params)
@@ -259,6 +285,40 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
259285
return CScriptID(hash);
260286
}
261287
}
288+
data.clear();
289+
auto bech = bech32::Decode(str);
290+
if (bech.second.size() > 0 && bech.first == params.Bech32HRP()) {
291+
// Bech32 decoding
292+
int version = bech.second[0]; // The first 5 bit symbol is the witness version (0-16)
293+
// The rest of the symbols are converted witness program bytes.
294+
if (ConvertBits<5, 8, false>(data, bech.second.begin() + 1, bech.second.end())) {
295+
if (version == 0) {
296+
{
297+
WitnessV0KeyHash keyid;
298+
if (data.size() == keyid.size()) {
299+
std::copy(data.begin(), data.end(), keyid.begin());
300+
return keyid;
301+
}
302+
}
303+
{
304+
WitnessV0ScriptHash scriptid;
305+
if (data.size() == scriptid.size()) {
306+
std::copy(data.begin(), data.end(), scriptid.begin());
307+
return scriptid;
308+
}
309+
}
310+
return CNoDestination();
311+
}
312+
if (version > 16 || data.size() < 2 || data.size() > 40) {
313+
return CNoDestination();
314+
}
315+
WitnessUnknown unk;
316+
unk.version = version;
317+
std::copy(data.begin(), data.end(), unk.program);
318+
unk.length = data.size();
319+
return unk;
320+
}
321+
}
262322
return CNoDestination();
263323
}
264324
} // namespace

src/chainparams.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ class CMainParams : public CChainParams {
137137
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
138138
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
139139

140+
bech32_hrp = "bc";
141+
140142
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
141143

142144
fDefaultConsistencyChecks = false;
@@ -236,6 +238,8 @@ class CTestNetParams : public CChainParams {
236238
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
237239
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
238240

241+
bech32_hrp = "tb";
242+
239243
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
240244

241245
fDefaultConsistencyChecks = false;
@@ -330,6 +334,8 @@ class CRegTestParams : public CChainParams {
330334
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
331335
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
332336
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
337+
338+
bech32_hrp = "bcrt";
333339
}
334340
};
335341

src/chainparams.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class CChainParams
7373
std::string NetworkIDString() const { return strNetworkID; }
7474
const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }
7575
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
76+
const std::string& Bech32HRP() const { return bech32_hrp; }
7677
const std::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; }
7778
const CCheckpointData& Checkpoints() const { return checkpointData; }
7879
const ChainTxData& TxData() const { return chainTxData; }
@@ -86,6 +87,7 @@ class CChainParams
8687
uint64_t nPruneAfterHeight;
8788
std::vector<CDNSSeedData> vSeeds;
8889
std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
90+
std::string bech32_hrp;
8991
std::string strNetworkID;
9092
CBlock genesis;
9193
std::vector<SeedSpec6> vFixedSeeds;

src/policy/policy.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool w
7676
else if (!witnessEnabled && (whichType == TX_WITNESS_V0_KEYHASH || whichType == TX_WITNESS_V0_SCRIPTHASH))
7777
return false;
7878

79-
return whichType != TX_NONSTANDARD;
79+
return whichType != TX_NONSTANDARD && whichType != TX_WITNESS_UNKNOWN;
8080
}
8181

8282
bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnessEnabled)

src/rpc/misc.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "chain.h"
88
#include "clientversion.h"
99
#include "core_io.h"
10+
#include "crypto/ripemd160.h"
1011
#include "init.h"
1112
#include "validation.h"
1213
#include "httpserver.h"
@@ -45,6 +46,7 @@ class DescribeAddressVisitor : public boost::static_visitor<UniValue>
4546
UniValue obj(UniValue::VOBJ);
4647
CPubKey vchPubKey;
4748
obj.push_back(Pair("isscript", false));
49+
obj.push_back(Pair("iswitness", false));
4850
if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) {
4951
obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
5052
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
@@ -56,6 +58,7 @@ class DescribeAddressVisitor : public boost::static_visitor<UniValue>
5658
UniValue obj(UniValue::VOBJ);
5759
CScript subscript;
5860
obj.push_back(Pair("isscript", true));
61+
obj.push_back(Pair("iswitness", false));
5962
if (pwallet && pwallet->GetCScript(scriptID, subscript)) {
6063
std::vector<CTxDestination> addresses;
6164
txnouttype whichType;
@@ -73,6 +76,47 @@ class DescribeAddressVisitor : public boost::static_visitor<UniValue>
7376
}
7477
return obj;
7578
}
79+
80+
UniValue operator()(const WitnessV0KeyHash& id) const
81+
{
82+
UniValue obj(UniValue::VOBJ);
83+
CPubKey pubkey;
84+
obj.push_back(Pair("isscript", false));
85+
obj.push_back(Pair("iswitness", true));
86+
obj.push_back(Pair("witness_version", 0));
87+
obj.push_back(Pair("witness_program", HexStr(id.begin(), id.end())));
88+
if (pwallet && pwallet->GetPubKey(CKeyID(id), pubkey)) {
89+
obj.push_back(Pair("pubkey", HexStr(pubkey)));
90+
}
91+
return obj;
92+
}
93+
94+
UniValue operator()(const WitnessV0ScriptHash& id) const
95+
{
96+
UniValue obj(UniValue::VOBJ);
97+
CScript subscript;
98+
obj.push_back(Pair("isscript", true));
99+
obj.push_back(Pair("iswitness", true));
100+
obj.push_back(Pair("witness_version", 0));
101+
obj.push_back(Pair("witness_program", HexStr(id.begin(), id.end())));
102+
CRIPEMD160 hasher;
103+
uint160 hash;
104+
hasher.Write(id.begin(), 32).Finalize(hash.begin());
105+
if (pwallet && pwallet->GetCScript(CScriptID(hash), subscript)) {
106+
obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
107+
}
108+
return obj;
109+
}
110+
111+
UniValue operator()(const WitnessUnknown& id) const
112+
{
113+
UniValue obj(UniValue::VOBJ);
114+
CScript subscript;
115+
obj.push_back(Pair("iswitness", true));
116+
obj.push_back(Pair("witness_version", (int)id.version));
117+
obj.push_back(Pair("witness_program", HexStr(id.program, id.program + id.length)));
118+
return obj;
119+
}
76120
};
77121
#endif
78122

src/script/ismine.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool&
6161
{
6262
case TX_NONSTANDARD:
6363
case TX_NULL_DATA:
64+
case TX_WITNESS_UNKNOWN:
6465
break;
6566
case TX_PUBKEY:
6667
keyID = CPubKey(vSolutions[0]).GetID();

src/script/sign.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP
7979
{
8080
case TX_NONSTANDARD:
8181
case TX_NULL_DATA:
82+
case TX_WITNESS_UNKNOWN:
8283
return false;
8384
case TX_PUBKEY:
8485
keyID = CPubKey(vSolutions[0]).GetID();
@@ -309,6 +310,7 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature
309310
{
310311
case TX_NONSTANDARD:
311312
case TX_NULL_DATA:
313+
case TX_WITNESS_UNKNOWN:
312314
// Don't know anything about this, assume bigger one is correct:
313315
if (sigs1.script.size() >= sigs2.script.size())
314316
return sigs1;

src/script/standard.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const char* GetTxnOutputType(txnouttype t)
3030
case TX_NULL_DATA: return "nulldata";
3131
case TX_WITNESS_V0_KEYHASH: return "witness_v0_keyhash";
3232
case TX_WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash";
33+
case TX_WITNESS_UNKNOWN: return "witness_unknown";
3334
}
3435
return nullptr;
3536
}
@@ -75,6 +76,12 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
7576
vSolutionsRet.push_back(witnessprogram);
7677
return true;
7778
}
79+
if (witnessversion != 0) {
80+
typeRet = TX_WITNESS_UNKNOWN;
81+
vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion});
82+
vSolutionsRet.push_back(std::move(witnessprogram));
83+
return true;
84+
}
7885
return false;
7986
}
8087

@@ -198,6 +205,23 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
198205
{
199206
addressRet = CScriptID(uint160(vSolutions[0]));
200207
return true;
208+
} else if (whichType == TX_WITNESS_V0_KEYHASH) {
209+
WitnessV0KeyHash hash;
210+
std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
211+
addressRet = hash;
212+
return true;
213+
} else if (whichType == TX_WITNESS_V0_SCRIPTHASH) {
214+
WitnessV0ScriptHash hash;
215+
std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
216+
addressRet = hash;
217+
return true;
218+
} else if (whichType == TX_WITNESS_UNKNOWN) {
219+
WitnessUnknown unk;
220+
unk.version = vSolutions[0][0];
221+
std::copy(vSolutions[1].begin(), vSolutions[1].end(), unk.program);
222+
unk.length = vSolutions[1].size();
223+
addressRet = unk;
224+
return true;
201225
}
202226
// Multisig txns have more than one address...
203227
return false;
@@ -268,6 +292,27 @@ class CScriptVisitor : public boost::static_visitor<bool>
268292
*script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
269293
return true;
270294
}
295+
296+
bool operator()(const WitnessV0KeyHash& id) const
297+
{
298+
script->clear();
299+
*script << OP_0 << ToByteVector(id);
300+
return true;
301+
}
302+
303+
bool operator()(const WitnessV0ScriptHash& id) const
304+
{
305+
script->clear();
306+
*script << OP_0 << ToByteVector(id);
307+
return true;
308+
}
309+
310+
bool operator()(const WitnessUnknown& id) const
311+
{
312+
script->clear();
313+
*script << CScript::EncodeOP_N(id.version) << std::vector<unsigned char>(id.program, id.program + id.length);
314+
return true;
315+
}
271316
};
272317
} // namespace
273318

src/script/standard.h

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ enum txnouttype
6464
TX_NULL_DATA, //!< unspendable OP_RETURN script that carries data
6565
TX_WITNESS_V0_SCRIPTHASH,
6666
TX_WITNESS_V0_KEYHASH,
67+
TX_WITNESS_UNKNOWN, //!< Only for Witness versions not already defined above
6768
};
6869

6970
class CNoDestination {
@@ -72,14 +73,42 @@ class CNoDestination {
7273
friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; }
7374
};
7475

76+
struct WitnessV0ScriptHash : public uint256 {};
77+
struct WitnessV0KeyHash : public uint160 {};
78+
79+
//! CTxDestination subtype to encode any future Witness version
80+
struct WitnessUnknown
81+
{
82+
unsigned int version;
83+
unsigned int length;
84+
unsigned char program[40];
85+
86+
friend bool operator==(const WitnessUnknown& w1, const WitnessUnknown& w2) {
87+
if (w1.version != w2.version) return false;
88+
if (w1.length != w2.length) return false;
89+
return std::equal(w1.program, w1.program + w1.length, w2.program);
90+
}
91+
92+
friend bool operator<(const WitnessUnknown& w1, const WitnessUnknown& w2) {
93+
if (w1.version < w2.version) return true;
94+
if (w1.version > w2.version) return false;
95+
if (w1.length < w2.length) return true;
96+
if (w1.length > w2.length) return false;
97+
return std::lexicographical_compare(w1.program, w1.program + w1.length, w2.program, w2.program + w2.length);
98+
}
99+
};
100+
75101
/**
76102
* A txout script template with a specific destination. It is either:
77103
* * CNoDestination: no destination set
78-
* * CKeyID: TX_PUBKEYHASH destination
79-
* * CScriptID: TX_SCRIPTHASH destination
104+
* * CKeyID: TX_PUBKEYHASH destination (P2PKH)
105+
* * CScriptID: TX_SCRIPTHASH destination (P2SH)
106+
* * WitnessV0ScriptHash: TX_WITNESS_V0_SCRIPTHASH destination (P2WSH)
107+
* * WitnessV0KeyHash: TX_WITNESS_V0_KEYHASH destination (P2WPKH)
108+
* * WitnessUnknown: TX_WITNESS_UNKNOWN destination (P2W???)
80109
* A CTxDestination is the internal data type encoded in a bitcoin address
81110
*/
82-
typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
111+
typedef boost::variant<CNoDestination, CKeyID, CScriptID, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown> CTxDestination;
83112

84113
/** Check whether a CTxDestination is a CNoDestination. */
85114
bool IsValidDestination(const CTxDestination& dest);
@@ -104,7 +133,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
104133
* Parse a standard scriptPubKey for the destination address. Assigns result to
105134
* the addressRet parameter and returns true if successful. For multisig
106135
* scripts, instead use ExtractDestinations. Currently only works for P2PK,
107-
* P2PKH, and P2SH scripts.
136+
* P2PKH, P2SH, P2WPKH, and P2WSH scripts.
108137
*/
109138
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
110139

0 commit comments

Comments
 (0)