From c091b99379b97cb314c9fa123beabdbc324cf7a4 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 25 Aug 2017 19:55:52 -0700 Subject: Implement BIP173 addresses and tests --- src/script/ismine.cpp | 1 + src/script/sign.cpp | 2 ++ src/script/standard.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/script/standard.h | 37 +++++++++++++++++++++++++++++++++---- 4 files changed, 81 insertions(+), 4 deletions(-) (limited to 'src/script') diff --git a/src/script/ismine.cpp b/src/script/ismine.cpp index c3aade1774..6b68f0679e 100644 --- a/src/script/ismine.cpp +++ b/src/script/ismine.cpp @@ -61,6 +61,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey, bool& { case TX_NONSTANDARD: case TX_NULL_DATA: + case TX_WITNESS_UNKNOWN: break; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); diff --git a/src/script/sign.cpp b/src/script/sign.cpp index dc50467d3f..ac58b690a2 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -79,6 +79,7 @@ static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptP { case TX_NONSTANDARD: case TX_NULL_DATA: + case TX_WITNESS_UNKNOWN: return false; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); @@ -309,6 +310,7 @@ static Stacks CombineSignatures(const CScript& scriptPubKey, const BaseSignature { case TX_NONSTANDARD: case TX_NULL_DATA: + case TX_WITNESS_UNKNOWN: // Don't know anything about this, assume bigger one is correct: if (sigs1.script.size() >= sigs2.script.size()) return sigs1; diff --git a/src/script/standard.cpp b/src/script/standard.cpp index b6e2232ab4..f57f1f61b4 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -30,6 +30,7 @@ const char* GetTxnOutputType(txnouttype t) case TX_NULL_DATA: return "nulldata"; case TX_WITNESS_V0_KEYHASH: return "witness_v0_keyhash"; case TX_WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash"; + case TX_WITNESS_UNKNOWN: return "witness_unknown"; } return nullptr; } @@ -75,6 +76,12 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector{(unsigned char)witnessversion}); + vSolutionsRet.push_back(std::move(witnessprogram)); + return true; + } return false; } @@ -198,6 +205,23 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) { addressRet = CScriptID(uint160(vSolutions[0])); return true; + } else if (whichType == TX_WITNESS_V0_KEYHASH) { + WitnessV0KeyHash hash; + std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin()); + addressRet = hash; + return true; + } else if (whichType == TX_WITNESS_V0_SCRIPTHASH) { + WitnessV0ScriptHash hash; + std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin()); + addressRet = hash; + return true; + } else if (whichType == TX_WITNESS_UNKNOWN) { + WitnessUnknown unk; + unk.version = vSolutions[0][0]; + std::copy(vSolutions[1].begin(), vSolutions[1].end(), unk.program); + unk.length = vSolutions[1].size(); + addressRet = unk; + return true; } // Multisig txns have more than one address... return false; @@ -268,6 +292,27 @@ public: *script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL; return true; } + + bool operator()(const WitnessV0KeyHash& id) const + { + script->clear(); + *script << OP_0 << ToByteVector(id); + return true; + } + + bool operator()(const WitnessV0ScriptHash& id) const + { + script->clear(); + *script << OP_0 << ToByteVector(id); + return true; + } + + bool operator()(const WitnessUnknown& id) const + { + script->clear(); + *script << CScript::EncodeOP_N(id.version) << std::vector(id.program, id.program + id.length); + return true; + } }; } // namespace diff --git a/src/script/standard.h b/src/script/standard.h index 8df143a3a3..fa07ea88c1 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -64,6 +64,7 @@ enum txnouttype TX_NULL_DATA, //!< unspendable OP_RETURN script that carries data TX_WITNESS_V0_SCRIPTHASH, TX_WITNESS_V0_KEYHASH, + TX_WITNESS_UNKNOWN, //!< Only for Witness versions not already defined above }; class CNoDestination { @@ -72,14 +73,42 @@ public: friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; } }; +struct WitnessV0ScriptHash : public uint256 {}; +struct WitnessV0KeyHash : public uint160 {}; + +//! CTxDestination subtype to encode any future Witness version +struct WitnessUnknown +{ + unsigned int version; + unsigned int length; + unsigned char program[40]; + + friend bool operator==(const WitnessUnknown& w1, const WitnessUnknown& w2) { + if (w1.version != w2.version) return false; + if (w1.length != w2.length) return false; + return std::equal(w1.program, w1.program + w1.length, w2.program); + } + + friend bool operator<(const WitnessUnknown& w1, const WitnessUnknown& w2) { + if (w1.version < w2.version) return true; + if (w1.version > w2.version) return false; + if (w1.length < w2.length) return true; + if (w1.length > w2.length) return false; + return std::lexicographical_compare(w1.program, w1.program + w1.length, w2.program, w2.program + w2.length); + } +}; + /** * A txout script template with a specific destination. It is either: * * CNoDestination: no destination set - * * CKeyID: TX_PUBKEYHASH destination - * * CScriptID: TX_SCRIPTHASH destination + * * CKeyID: TX_PUBKEYHASH destination (P2PKH) + * * CScriptID: TX_SCRIPTHASH destination (P2SH) + * * WitnessV0ScriptHash: TX_WITNESS_V0_SCRIPTHASH destination (P2WSH) + * * WitnessV0KeyHash: TX_WITNESS_V0_KEYHASH destination (P2WPKH) + * * WitnessUnknown: TX_WITNESS_UNKNOWN destination (P2W???) * A CTxDestination is the internal data type encoded in a bitcoin address */ -typedef boost::variant CTxDestination; +typedef boost::variant CTxDestination; /** Check whether a CTxDestination is a CNoDestination. */ bool IsValidDestination(const CTxDestination& dest); @@ -104,7 +133,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector