mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-06 03:02:37 +02:00
Merge #11167: Full BIP173 (Bech32) support
8213838[Qt] tolerate BIP173/bech32 addresses during input validation (Jonas Schnelli)06eaca6[RPC] Wallet: test importing of native witness scripts (NicolasDorier)fd0041aUse BIP173 addresses in segwit.py test (Pieter Wuille)e278f12Support BIP173 in addwitnessaddress (Pieter Wuille)c091b99Implement BIP173 addresses and tests (Pieter Wuille)bd355b8Add regtest testing to base58_tests (Pieter Wuille)6565c55Convert base58_tests from type/payload to scriptPubKey comparison (Pieter Wuille)8fd2267Import Bech32 C++ reference code & tests (Pieter Wuille)1e46ebdImplement {Encode,Decode}Destination without CBitcoinAddress (Pieter Wuille) Pull request description: Builds on top of #11117. This adds support for: * Creating BIP173 addresses for testing (through `addwitnessaddress`, though by default it still produces P2SH versions) * Sending to BIP173 addresses (including non-v0 ones) * Analysing BIP173 addresses (through `validateaddress`) It includes a reformatted version of the [C++ Bech32 reference code](https://github.com/sipa/bech32/tree/master/ref/c%2B%2B) and an independent implementation of the address encoding/decoding logic (integrated with CTxDestination). All BIP173 test vectors are included. Not included (and intended for other PRs): * Full wallet support for SegWit (which would include automatically adding witness scripts to the wallet during automatic keypool topup, SegWit change outputs, ...) [see #11403] * Splitting base58.cpp and tests/base58_tests.cpp up into base58-specific code, and "address encoding"-code [see #11372] * Error locating in UI for BIP173 addresses. Tree-SHA512: 238031185fd07f3ac873c586043970cc2db91bf7735c3c168cb33a3db39a7bda81d4891b649685bb17ef90dc63af0328e7705d8cd3e8dafd6c4d3c08fb230341
This commit is contained in:
@@ -1154,11 +1154,10 @@ class Witnessifier : public boost::static_visitor<bool>
|
||||
{
|
||||
public:
|
||||
CWallet * const pwallet;
|
||||
CScriptID result;
|
||||
CTxDestination result;
|
||||
bool already_witness;
|
||||
|
||||
explicit Witnessifier(CWallet *_pwallet) : pwallet(_pwallet) {}
|
||||
|
||||
bool operator()(const CNoDestination &dest) const { return false; }
|
||||
explicit Witnessifier(CWallet *_pwallet) : pwallet(_pwallet), already_witness(false) {}
|
||||
|
||||
bool operator()(const CKeyID &keyID) {
|
||||
if (pwallet) {
|
||||
@@ -1172,9 +1171,7 @@ public:
|
||||
!VerifyScript(sigs.scriptSig, witscript, &sigs.scriptWitness, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, DummySignatureCreator(pwallet).Checker())) {
|
||||
return false;
|
||||
}
|
||||
pwallet->AddCScript(witscript);
|
||||
result = CScriptID(witscript);
|
||||
return true;
|
||||
return ExtractDestination(witscript, result);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1185,7 +1182,8 @@ public:
|
||||
int witnessversion;
|
||||
std::vector<unsigned char> witprog;
|
||||
if (subscript.IsWitnessProgram(witnessversion, witprog)) {
|
||||
result = scriptID;
|
||||
ExtractDestination(subscript, result);
|
||||
already_witness = true;
|
||||
return true;
|
||||
}
|
||||
CScript witscript = GetScriptForWitness(subscript);
|
||||
@@ -1197,12 +1195,27 @@ public:
|
||||
!VerifyScript(sigs.scriptSig, witscript, &sigs.scriptWitness, MANDATORY_SCRIPT_VERIFY_FLAGS | SCRIPT_VERIFY_WITNESS_PUBKEYTYPE, DummySignatureCreator(pwallet).Checker())) {
|
||||
return false;
|
||||
}
|
||||
pwallet->AddCScript(witscript);
|
||||
result = CScriptID(witscript);
|
||||
return true;
|
||||
return ExtractDestination(witscript, result);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator()(const WitnessV0KeyHash& id)
|
||||
{
|
||||
already_witness = true;
|
||||
result = id;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator()(const WitnessV0ScriptHash& id)
|
||||
{
|
||||
already_witness = true;
|
||||
result = id;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool operator()(const T& dest) { return false; }
|
||||
};
|
||||
|
||||
UniValue addwitnessaddress(const JSONRPCRequest& request)
|
||||
@@ -1212,17 +1225,18 @@ UniValue addwitnessaddress(const JSONRPCRequest& request)
|
||||
return NullUniValue;
|
||||
}
|
||||
|
||||
if (request.fHelp || request.params.size() < 1 || request.params.size() > 1)
|
||||
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
|
||||
{
|
||||
std::string msg = "addwitnessaddress \"address\"\n"
|
||||
std::string msg = "addwitnessaddress \"address\" ( p2sh )\n"
|
||||
"\nAdd a witness address for a script (with pubkey or redeemscript known).\n"
|
||||
"It returns the witness script.\n"
|
||||
|
||||
"\nArguments:\n"
|
||||
"1. \"address\" (string, required) An address known to the wallet\n"
|
||||
"2. p2sh (bool, optional, default=true) Embed inside P2SH\n"
|
||||
|
||||
"\nResult:\n"
|
||||
"\"witnessaddress\", (string) The value of the new address (P2SH of witness script).\n"
|
||||
"\"witnessaddress\", (string) The value of the new address (P2SH or BIP173).\n"
|
||||
"}\n"
|
||||
;
|
||||
throw std::runtime_error(msg);
|
||||
@@ -1240,13 +1254,31 @@ UniValue addwitnessaddress(const JSONRPCRequest& request)
|
||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
|
||||
}
|
||||
|
||||
bool p2sh = true;
|
||||
if (!request.params[1].isNull()) {
|
||||
p2sh = request.params[1].get_bool();
|
||||
}
|
||||
|
||||
Witnessifier w(pwallet);
|
||||
bool ret = boost::apply_visitor(w, dest);
|
||||
if (!ret) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Public key or redeemscript not known to wallet, or the key is uncompressed");
|
||||
}
|
||||
|
||||
pwallet->SetAddressBook(w.result, "", "receive");
|
||||
CScript witprogram = GetScriptForDestination(w.result);
|
||||
|
||||
if (p2sh) {
|
||||
w.result = CScriptID(witprogram);
|
||||
}
|
||||
|
||||
if (w.already_witness) {
|
||||
if (!(dest == w.result)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot convert between witness address types");
|
||||
}
|
||||
} else {
|
||||
pwallet->AddCScript(witprogram);
|
||||
pwallet->SetAddressBook(w.result, "", "receive");
|
||||
}
|
||||
|
||||
return EncodeDestination(w.result);
|
||||
}
|
||||
@@ -3199,7 +3231,7 @@ static const CRPCCommand commands[] =
|
||||
{ "wallet", "abandontransaction", &abandontransaction, {"txid"} },
|
||||
{ "wallet", "abortrescan", &abortrescan, {} },
|
||||
{ "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","account"} },
|
||||
{ "wallet", "addwitnessaddress", &addwitnessaddress, {"address"} },
|
||||
{ "wallet", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} },
|
||||
{ "wallet", "backupwallet", &backupwallet, {"destination"} },
|
||||
{ "wallet", "bumpfee", &bumpfee, {"txid", "options"} },
|
||||
{ "wallet", "dumpprivkey", &dumpprivkey, {"address"} },
|
||||
|
||||
@@ -111,7 +111,26 @@ public:
|
||||
Process(script);
|
||||
}
|
||||
|
||||
void operator()(const CNoDestination &none) {}
|
||||
void operator()(const WitnessV0ScriptHash& scriptID)
|
||||
{
|
||||
CScriptID id;
|
||||
CRIPEMD160().Write(scriptID.begin(), 32).Finalize(id.begin());
|
||||
CScript script;
|
||||
if (keystore.GetCScript(id, script)) {
|
||||
Process(script);
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(const WitnessV0KeyHash& keyid)
|
||||
{
|
||||
CKeyID id(keyid);
|
||||
if (keystore.HaveKey(id)) {
|
||||
vKeys.push_back(id);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename X>
|
||||
void operator()(const X &none) {}
|
||||
};
|
||||
|
||||
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
|
||||
|
||||
Reference in New Issue
Block a user