add unit tests for p2wsh and p2sh(p2wsh)

This commit is contained in:
jc 2018-02-24 17:38:30 -05:00
parent a4e0e3a922
commit 23eb4a5bbe
No known key found for this signature in database
GPG Key ID: E87FC0C8A375F3CF
7 changed files with 216 additions and 21 deletions

View File

@ -216,6 +216,9 @@ public:
bool operator()(const CKeyID& id) const { return addr->Set(id); }
bool operator()(const CScriptID& id) const { return addr->Set(id); }
bool operator()(const WitnessV0ScriptHash& w) const { return false; }
bool operator()(const WitnessV0KeyHash& w) const { return false; }
bool operator()(const WitnessUnknown& w) const { return false; }
bool operator()(const CNoDestination& no) const { return false; }
};
@ -386,4 +389,3 @@ libzcash::SpendingKey CZCSpendingKey::Get() const
ss >> ret;
return ret;
}

View File

@ -145,6 +145,47 @@ public:
}
return obj;
}
UniValue operator()(const WitnessV0KeyHash& id) const
{
UniValue obj(UniValue::VOBJ);
CPubKey pubkey;
obj.pushKV("isscript", false);
obj.pushKV("iswitness", true);
obj.pushKV("witness_version", 0);
obj.pushKV("witness_program", HexStr(id.begin(), id.end()));
//if (pwallet && pwallet->GetPubKey(CKeyID(id), pubkey)) {
//obj.pushKV("pubkey", HexStr(pubkey));
//}
return obj;
}
UniValue operator()(const WitnessV0ScriptHash& id) const
{
UniValue obj(UniValue::VOBJ);
CScript subscript;
obj.pushKV("isscript", true);
obj.pushKV("iswitness", true);
obj.pushKV("witness_version", 0);
obj.pushKV("witness_program", HexStr(id.begin(), id.end()));
CRIPEMD160 hasher;
uint160 hash;
hasher.Write(id.begin(), 32).Finalize(hash.begin());
//if (pwallet && pwallet->GetCScript(CScriptID(hash), subscript)) {
//ProcessSubScript(subscript, obj);
//}
return obj;
}
UniValue operator()(const WitnessUnknown& id) const
{
UniValue obj(UniValue::VOBJ);
CScript subscript;
obj.pushKV("iswitness", true);
obj.pushKV("witness_version", (int)id.version);
obj.pushKV("witness_program", HexStr(id.program, id.program + id.length));
return obj;
}
};
#endif

View File

@ -26,13 +26,13 @@ const char* GetTxnOutputType(txnouttype t)
{
case TX_NONSTANDARD: return "nonstandard";
case TX_PUBKEY: return "pubkey";
case TX_PUBKEY_REPLAY: return "pubkeyreplay";
case TX_PUBKEYHASH: return "pubkeyhash";
case TX_PUBKEYHASH_REPLAY: return "pubkeyhashreplay";
case TX_SCRIPTHASH: return "scripthash";
case TX_MULTISIG: return "multisig";
case TX_MULTISIG_REPLAY: return "multisigreplay";
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 NULL;
}
@ -48,15 +48,12 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
{
// Standard tx, sender provides pubkey, receiver adds signature
mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
mTemplates.insert(make_pair(TX_PUBKEY_REPLAY, CScript() << OP_PUBKEY << OP_CHECKSIG << OP_SMALLDATA << OP_SMALLDATA << OP_NOP5));
// Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
mTemplates.insert(make_pair(TX_PUBKEYHASH_REPLAY, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG << OP_SMALLDATA << OP_SMALLDATA << OP_NOP5));
// Sender provides N pubkeys, receivers provides M signatures
mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
mTemplates.insert(make_pair(TX_MULTISIG_REPLAY, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG << OP_SMALLDATA << OP_SMALLDATA << OP_NOP5));
// Empty, provably prunable, data-carrying output
if (GetBoolArg("-datacarrier", true))
@ -301,6 +298,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<unsigned char>(id.program, id.program + id.length);
return true;
}
};
}
@ -322,3 +340,21 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
return script;
}
CScript GetScriptForWitness(const CScript& redeemscript)
{
CScript ret;
txnouttype typ;
std::vector<std::vector<unsigned char> > vSolutions;
if (Solver(redeemscript, typ, vSolutions)) {
if (typ == TX_PUBKEY) {
return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end())));
} else if (typ == TX_PUBKEYHASH) {
return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0]));
}
}
uint256 hash;
CSHA256().Write(&redeemscript[0], redeemscript.size()).Finalize(hash.begin());
return GetScriptForDestination(WitnessV0ScriptHash(hash));
}

View File

@ -63,13 +63,13 @@ enum txnouttype
TX_NONSTANDARD,
// 'standard' transaction types:
TX_PUBKEY,
TX_PUBKEY_REPLAY,
TX_PUBKEYHASH,
TX_PUBKEYHASH_REPLAY,
TX_SCRIPTHASH,
TX_MULTISIG,
TX_MULTISIG_REPLAY,
TX_NULL_DATA,
TX_WITNESS_V0_SCRIPTHASH,
TX_WITNESS_V0_KEYHASH,
TX_WITNESS_UNKNOWN, //!< Only for Witness versions not already defined above
};
class CNoDestination {
@ -78,6 +78,42 @@ public:
friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; }
};
struct WitnessV0ScriptHash : public uint256
{
WitnessV0ScriptHash() : uint256() {}
explicit WitnessV0ScriptHash(const uint256& hash) : uint256(hash) {}
using uint256::uint256;
};
struct WitnessV0KeyHash : public uint160
{
WitnessV0KeyHash() : uint160() {}
explicit WitnessV0KeyHash(const uint160& hash) : uint160(hash) {}
using uint160::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
@ -85,7 +121,7 @@ public:
* * CScriptID: TX_SCRIPTHASH destination
* A CTxDestination is the internal data type encoded in a CBitcoinAddress
*/
typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
typedef boost::variant<CNoDestination, CKeyID, CScriptID, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown> CTxDestination;
const char* GetTxnOutputType(txnouttype t);
@ -97,5 +133,6 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::
CScript GetScriptForDestination(const CTxDestination& dest);
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
CScript GetScriptForWitness(const CScript& redeemscript);
#endif // BITCOIN_SCRIPT_STANDARD_H

View File

@ -92,6 +92,9 @@ public:
{
return (exp_addrType == "none");
}
template<typename X>
bool operator()(const X &none) const { return false; }
};
// Visitor to check address payload
@ -115,6 +118,9 @@ public:
{
return exp_payload.size() == 0;
}
template<typename X>
bool operator()(const X &none) { return false; }
};
// Goal: check that parsed keys match test payload
@ -271,4 +277,3 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid)
BOOST_AUTO_TEST_SUITE_END()

View File

@ -44,7 +44,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri
txTo.vin[0].scriptSig = scriptSig;
txTo.vout[0].nValue = 1;
return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0), &err);
return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0), &err);
}
@ -123,7 +123,7 @@ BOOST_AUTO_TEST_CASE(sign)
txTo[i].vin[0].scriptSig = sigSave;
}
}
/*
BOOST_AUTO_TEST_CASE(segwitlock)
{
ScriptError err;
@ -158,6 +158,61 @@ BOOST_AUTO_TEST_CASE(segwitlock)
BOOST_CHECK(!Verify(p2shp2wshsig, p2shp2wsh, true, err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SEGWIT_LOCKED, ScriptErrorString(err));
}
*/
BOOST_AUTO_TEST_CASE(segwitspend_wsh)
{
ScriptError err;
CScript unwrappedPubKey,scriptSig;
unwrappedPubKey << OP_12 << OP_EQUAL;
scriptSig << OP_12;
CScript p2shPubKey = GetScriptForDestination(CScriptID(unwrappedPubKey));
CScript p2shScriptSig = scriptSig;
p2shScriptSig << Serialize(unwrappedPubKey);
CScript segwitPubKey = GetScriptForWitness(unwrappedPubKey);
CScript segwitScriptSig = scriptSig;
segwitScriptSig << Serialize(unwrappedPubKey);
CScript p2shsegwitPubKey = GetScriptForDestination(CScriptID(segwitPubKey));
CScript p2shsegwitScriptSig = segwitScriptSig;
p2shsegwitScriptSig << Serialize(segwitPubKey);
BOOST_CHECK(Verify(scriptSig, unwrappedPubKey, true, err));
BOOST_CHECK(Verify(p2shScriptSig, p2shPubKey, true, err));
BOOST_CHECK(segwitPubKey.IsPayToWitnessScriptHash());
BOOST_CHECK(Verify(segwitScriptSig, segwitPubKey, true, err));
BOOST_CHECK(Verify(p2shsegwitScriptSig, p2shsegwitPubKey, true, err));
}
/*
BOOST_AUTO_TEST_CASE(segwitspend_wpkh)
{
ScriptError err;
CScript unwrappedPubKey,scriptSig;
unwrappedPubKey << OP_DUP << OP_HASH160 << pubkeyhash << OP_EQUALVERIFY << OP_CHECKSIG;
scriptSig << Sign() << pubkey;
CScript p2shPubKey = GetScriptForDestination(CScriptID(unwrappedPubKey));
CScript p2shScriptSig = scriptSig;
p2shScriptSig << Serialize(unwrappedPubKey);
CScript segwitPubKey = GetScriptForDestination(WitnessV0KeyHash(unwrappedPubKey));
CScript segwitScriptSig = p2shScriptSig;
CScript p2shsegwitPubKey = GetScriptForDestination(CScriptID(segwitPubKey));
CScript p2shsegwitScriptSig = segwitScriptSig;
p2shsegwitScriptSig << Serialize(segwitPubKey);
BOOST_CHECK(Verify(scriptSig, unwrappedPubKey, true, err));
BOOST_CHECK(Verify(p2shScriptSig, p2shPubKey, true, err));
BOOST_CHECK(Verify(segwitScriptSig, segwitPubKey, true, err));
BOOST_CHECK(Verify(p2shsegwitScriptSig, p2shsegwitpubkey, true, err));
}
/**/
BOOST_AUTO_TEST_CASE(norecurse)
{

View File

@ -169,7 +169,7 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
const vector<unsigned char> &vchCryptedSecret)
{
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
if (!fFileBacked)
@ -477,7 +477,7 @@ bool CWallet::Verify(const string& walletFile, string& warningString, string& er
} catch (const boost::filesystem::filesystem_error&) {
// failure is ok (well, not really, but it's not worse than what we started with)
}
// try again
if (!bitdb.Open(GetDataDir())) {
// if it still fails, it probably means we can't even create the database env
@ -486,14 +486,14 @@ bool CWallet::Verify(const string& walletFile, string& warningString, string& er
return true;
}
}
if (GetBoolArg("-salvagewallet", false))
{
// Recover readable keypairs:
if (!CWalletDB::Recover(bitdb, walletFile, true))
return false;
}
if (boost::filesystem::exists(GetDataDir() / walletFile))
{
CDBEnv::VerifyResult r = bitdb.Verify(walletFile, CWalletDB::Recover);
@ -507,7 +507,7 @@ bool CWallet::Verify(const string& walletFile, string& warningString, string& er
if (r == CDBEnv::RECOVER_FAIL)
errorString += _("wallet.dat corrupt, salvage failed");
}
return true;
}
@ -2993,7 +2993,7 @@ bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
/**
* Mark old keypool keys as used,
* and generate all new keys
* and generate all new keys
*/
bool CWallet::NewKeyPool()
{
@ -3406,7 +3406,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) {}
};
void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {