add unit tests for p2wsh and p2sh(p2wsh)
This commit is contained in:
parent
a4e0e3a922
commit
23eb4a5bbe
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue