Merge pull request #91 from jc23424/segwit-tests
Add more tests on FORKID (replay) and modified segwit spends
This commit is contained in:
commit
7f2662522c
|
@ -216,6 +216,9 @@ public:
|
||||||
|
|
||||||
bool operator()(const CKeyID& id) const { return addr->Set(id); }
|
bool operator()(const CKeyID& id) const { return addr->Set(id); }
|
||||||
bool operator()(const CScriptID& 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; }
|
bool operator()(const CNoDestination& no) const { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -386,4 +389,3 @@ libzcash::SpendingKey CZCSpendingKey::Get() const
|
||||||
ss >> ret;
|
ss >> ret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -145,6 +145,47 @@ public:
|
||||||
}
|
}
|
||||||
return obj;
|
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
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -26,13 +26,13 @@ const char* GetTxnOutputType(txnouttype t)
|
||||||
{
|
{
|
||||||
case TX_NONSTANDARD: return "nonstandard";
|
case TX_NONSTANDARD: return "nonstandard";
|
||||||
case TX_PUBKEY: return "pubkey";
|
case TX_PUBKEY: return "pubkey";
|
||||||
case TX_PUBKEY_REPLAY: return "pubkeyreplay";
|
|
||||||
case TX_PUBKEYHASH: return "pubkeyhash";
|
case TX_PUBKEYHASH: return "pubkeyhash";
|
||||||
case TX_PUBKEYHASH_REPLAY: return "pubkeyhashreplay";
|
|
||||||
case TX_SCRIPTHASH: return "scripthash";
|
case TX_SCRIPTHASH: return "scripthash";
|
||||||
case TX_MULTISIG: return "multisig";
|
case TX_MULTISIG: return "multisig";
|
||||||
case TX_MULTISIG_REPLAY: return "multisigreplay";
|
|
||||||
case TX_NULL_DATA: return "nulldata";
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -48,15 +48,12 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsi
|
||||||
{
|
{
|
||||||
// Standard tx, sender provides pubkey, receiver adds signature
|
// 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, 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
|
// 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, 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
|
// 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, 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
|
// Empty, provably prunable, data-carrying output
|
||||||
if (GetBoolArg("-datacarrier", true))
|
if (GetBoolArg("-datacarrier", true))
|
||||||
|
@ -301,6 +298,27 @@ public:
|
||||||
*script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
|
*script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
|
||||||
return true;
|
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;
|
script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
|
||||||
return script;
|
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,
|
TX_NONSTANDARD,
|
||||||
// 'standard' transaction types:
|
// 'standard' transaction types:
|
||||||
TX_PUBKEY,
|
TX_PUBKEY,
|
||||||
TX_PUBKEY_REPLAY,
|
|
||||||
TX_PUBKEYHASH,
|
TX_PUBKEYHASH,
|
||||||
TX_PUBKEYHASH_REPLAY,
|
|
||||||
TX_SCRIPTHASH,
|
TX_SCRIPTHASH,
|
||||||
TX_MULTISIG,
|
TX_MULTISIG,
|
||||||
TX_MULTISIG_REPLAY,
|
|
||||||
TX_NULL_DATA,
|
TX_NULL_DATA,
|
||||||
|
TX_WITNESS_V0_SCRIPTHASH,
|
||||||
|
TX_WITNESS_V0_KEYHASH,
|
||||||
|
TX_WITNESS_UNKNOWN, //!< Only for Witness versions not already defined above
|
||||||
};
|
};
|
||||||
|
|
||||||
class CNoDestination {
|
class CNoDestination {
|
||||||
|
@ -78,6 +78,42 @@ public:
|
||||||
friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; }
|
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:
|
* A txout script template with a specific destination. It is either:
|
||||||
* * CNoDestination: no destination set
|
* * CNoDestination: no destination set
|
||||||
|
@ -85,7 +121,7 @@ public:
|
||||||
* * CScriptID: TX_SCRIPTHASH destination
|
* * CScriptID: TX_SCRIPTHASH destination
|
||||||
* A CTxDestination is the internal data type encoded in a CBitcoinAddress
|
* 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);
|
const char* GetTxnOutputType(txnouttype t);
|
||||||
|
|
||||||
|
@ -97,5 +133,6 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::
|
||||||
|
|
||||||
CScript GetScriptForDestination(const CTxDestination& dest);
|
CScript GetScriptForDestination(const CTxDestination& dest);
|
||||||
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
|
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
|
||||||
|
CScript GetScriptForWitness(const CScript& redeemscript);
|
||||||
|
|
||||||
#endif // BITCOIN_SCRIPT_STANDARD_H
|
#endif // BITCOIN_SCRIPT_STANDARD_H
|
||||||
|
|
|
@ -92,6 +92,9 @@ public:
|
||||||
{
|
{
|
||||||
return (exp_addrType == "none");
|
return (exp_addrType == "none");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename X>
|
||||||
|
bool operator()(const X &none) const { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Visitor to check address payload
|
// Visitor to check address payload
|
||||||
|
@ -115,6 +118,9 @@ public:
|
||||||
{
|
{
|
||||||
return exp_payload.size() == 0;
|
return exp_payload.size() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename X>
|
||||||
|
bool operator()(const X &none) { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Goal: check that parsed keys match test payload
|
// Goal: check that parsed keys match test payload
|
||||||
|
@ -271,4 +277,3 @@ BOOST_AUTO_TEST_CASE(base58_keys_invalid)
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,7 @@ Serialize(const CScript& s)
|
||||||
return sSerialized;
|
return sSerialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
CMutableTransaction BuildTransaction(const CScript& scriptSig, const CScript& scriptPubKey)
|
||||||
Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err)
|
|
||||||
{
|
{
|
||||||
// Create dummy to/from transactions:
|
// Create dummy to/from transactions:
|
||||||
CMutableTransaction txFrom;
|
CMutableTransaction txFrom;
|
||||||
|
@ -44,7 +43,14 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, Scri
|
||||||
txTo.vin[0].scriptSig = scriptSig;
|
txTo.vin[0].scriptSig = scriptSig;
|
||||||
txTo.vout[0].nValue = 1;
|
txTo.vout[0].nValue = 1;
|
||||||
|
|
||||||
return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0), &err);
|
return txTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err)
|
||||||
|
{
|
||||||
|
auto txTo = BuildTransaction(scriptSig, scriptPubKey);
|
||||||
|
return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS : SCRIPT_VERIFY_NONE, MutableTransactionSignatureChecker(&txTo, 0), &err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,39 +130,110 @@ BOOST_AUTO_TEST_CASE(sign)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(segwitlock)
|
BOOST_AUTO_TEST_CASE(segwitspend_wsh)
|
||||||
{
|
{
|
||||||
|
std::vector<bool> expects = {true, false};
|
||||||
|
|
||||||
|
for(auto it = expects.begin(); it != expects.end(); it++) {
|
||||||
|
bool expect = *it;
|
||||||
|
|
||||||
|
ScriptError err;
|
||||||
|
CScript unwrappedPubKey,scriptSig;
|
||||||
|
unwrappedPubKey << OP_12 << OP_EQUAL;
|
||||||
|
if(expect)
|
||||||
|
scriptSig << OP_12;
|
||||||
|
else
|
||||||
|
scriptSig << OP_11;
|
||||||
|
|
||||||
|
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) == expect);
|
||||||
|
BOOST_CHECK(Verify(p2shScriptSig, p2shPubKey, true, err) == expect);
|
||||||
|
|
||||||
|
BOOST_CHECK(p2shPubKey.IsPayToScriptHash());
|
||||||
|
BOOST_CHECK(segwitPubKey.IsPayToWitnessScriptHash());
|
||||||
|
BOOST_CHECK(p2shsegwitPubKey.IsPayToScriptHash());
|
||||||
|
|
||||||
|
BOOST_CHECK(Verify(segwitScriptSig, segwitPubKey, true, err) == expect);
|
||||||
|
BOOST_CHECK(Verify(p2shsegwitScriptSig, p2shsegwitPubKey, true, err) == expect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildPKTransaction(const CScript& scriptPubKey, CKey signingKey, CKey pushKey, CScript additionalSig, bool expect, ScriptError_t expect_err, const CScript& scriptToSign)
|
||||||
|
{
|
||||||
|
CMutableTransaction txTo = BuildTransaction(CScript(), scriptPubKey);
|
||||||
|
|
||||||
|
auto lenR = 32;
|
||||||
|
auto lenS = 32;
|
||||||
|
|
||||||
|
uint256 hash = SignatureHash(scriptToSign, txTo, 0, SIGHASH_ALL);
|
||||||
|
|
||||||
|
std::vector<unsigned char> vchSig;
|
||||||
|
signingKey.Sign(hash, vchSig, 0);
|
||||||
|
vchSig.push_back(static_cast<unsigned char>(SIGHASH_ALL));
|
||||||
|
|
||||||
|
txTo.vin[0].scriptSig << vchSig << ToByteVector(pushKey.GetPubKey());
|
||||||
|
txTo.vin[0].scriptSig += additionalSig;
|
||||||
|
|
||||||
ScriptError err;
|
ScriptError err;
|
||||||
|
BOOST_CHECK(Verify(txTo.vin[0].scriptSig, scriptPubKey, true, err) == expect);
|
||||||
|
|
||||||
// any scriptSig will do here
|
if(!expect)
|
||||||
CScript scriptSig;
|
BOOST_CHECK_MESSAGE(err == expect_err, ScriptErrorString(err));
|
||||||
scriptSig << ToByteVector(uint256());
|
}
|
||||||
|
|
||||||
uint160 hash20;
|
BOOST_AUTO_TEST_CASE(segwitspend_wpkh)
|
||||||
CScript p2wpkh;
|
{
|
||||||
p2wpkh << OP_0 << ToByteVector(hash20);
|
std::vector<bool> expects = {true, false};
|
||||||
BOOST_CHECK(!Verify(scriptSig, p2wpkh, true, err));
|
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SEGWIT_LOCKED, ScriptErrorString(err));
|
|
||||||
|
|
||||||
CScript p2shp2wpkh = GetScriptForDestination(CScriptID(p2wpkh));
|
CKey key1,key2;
|
||||||
CScript p2shp2wpkhsig = scriptSig;
|
key1.MakeNewKey(true);
|
||||||
p2shp2wpkhsig << Serialize(p2wpkh);
|
key2.MakeNewKey(true);
|
||||||
|
|
||||||
BOOST_CHECK(!Verify(p2shp2wpkhsig, p2shp2wpkh, true, err));
|
CScript unwrappedPubKey;
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SEGWIT_LOCKED, ScriptErrorString(err));
|
unwrappedPubKey << OP_DUP << OP_HASH160 << ToByteVector(key1.GetPubKey().GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||||
|
|
||||||
uint256 hash32;
|
for(auto it = expects.begin(); it != expects.end(); it++) {
|
||||||
CScript p2wsh;
|
bool expect = *it;
|
||||||
p2wsh << OP_0 << ToByteVector(hash32);
|
|
||||||
BOOST_CHECK(!Verify(scriptSig, p2wsh, true, err));
|
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SEGWIT_LOCKED, ScriptErrorString(err));
|
|
||||||
|
|
||||||
CScript p2shp2wsh = GetScriptForDestination(CScriptID(p2wsh));
|
CKey k = expect ? key1 : key2;
|
||||||
CScript p2shp2wshsig = scriptSig;
|
|
||||||
p2shp2wshsig << Serialize(p2wsh);
|
|
||||||
|
|
||||||
BOOST_CHECK(!Verify(p2shp2wshsig, p2shp2wsh, true, err));
|
CScript p2shPubKey = GetScriptForDestination(CScriptID(unwrappedPubKey));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SEGWIT_LOCKED, ScriptErrorString(err));
|
CScript segwitPubKey = GetScriptForWitness(unwrappedPubKey);
|
||||||
|
CScript p2shsegwitPubKey = GetScriptForDestination(CScriptID(segwitPubKey));
|
||||||
|
|
||||||
|
BOOST_CHECK(p2shPubKey.IsPayToScriptHash());
|
||||||
|
BOOST_CHECK(segwitPubKey.IsPayToWitnessPubKeyHash());
|
||||||
|
BOOST_CHECK(p2shsegwitPubKey.IsPayToScriptHash());
|
||||||
|
|
||||||
|
CScript p2shScriptSig;
|
||||||
|
p2shScriptSig << Serialize(unwrappedPubKey);
|
||||||
|
CScript segwitScriptSig = CScript();
|
||||||
|
CScript p2shsegwitScriptSig = segwitScriptSig;
|
||||||
|
p2shsegwitScriptSig << Serialize(segwitPubKey);
|
||||||
|
|
||||||
|
BuildPKTransaction(unwrappedPubKey, key1, k, CScript(), expect, SCRIPT_ERR_EQUALVERIFY, unwrappedPubKey);
|
||||||
|
BuildPKTransaction(p2shPubKey, key1, k, p2shScriptSig, expect, SCRIPT_ERR_EQUALVERIFY, unwrappedPubKey);
|
||||||
|
BuildPKTransaction(segwitPubKey, key1, k, segwitScriptSig, expect, SCRIPT_ERR_EQUALVERIFY, unwrappedPubKey);
|
||||||
|
BuildPKTransaction(p2shsegwitPubKey, key1, k, p2shsegwitScriptSig, expect, SCRIPT_ERR_EQUALVERIFY, unwrappedPubKey);
|
||||||
|
|
||||||
|
if(!expect) {
|
||||||
|
BuildPKTransaction(unwrappedPubKey, k, key1, CScript(), expect, SCRIPT_ERR_EVAL_FALSE, unwrappedPubKey);
|
||||||
|
BuildPKTransaction(p2shPubKey, k, key1, p2shScriptSig, expect, SCRIPT_ERR_EVAL_FALSE, unwrappedPubKey);
|
||||||
|
BuildPKTransaction(segwitPubKey, k, key1, segwitScriptSig, expect, SCRIPT_ERR_EVAL_FALSE, unwrappedPubKey);
|
||||||
|
BuildPKTransaction(p2shsegwitPubKey, k, key1, p2shsegwitScriptSig, expect, SCRIPT_ERR_EVAL_FALSE, unwrappedPubKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(norecurse)
|
BOOST_AUTO_TEST_CASE(norecurse)
|
||||||
|
|
|
@ -99,6 +99,17 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bo
|
||||||
stream << tx2;
|
stream << tx2;
|
||||||
BOOST_CHECK_MESSAGE(zcashconsensus_verify_script(begin_ptr(scriptPubKey), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, flags, NULL) == expect,message);
|
BOOST_CHECK_MESSAGE(zcashconsensus_verify_script(begin_ptr(scriptPubKey), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, flags, NULL) == expect,message);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// exercise the FORKID hashtype requirement
|
||||||
|
opcodetype op;
|
||||||
|
auto back = scriptPubKey.end() - 1;
|
||||||
|
if(scriptPubKey.GetOp(back, op) &&
|
||||||
|
op >= OP_CHECKSIG && op <= OP_CHECKSIGVERIFY) {
|
||||||
|
if(expect && scriptPubKey.GetSigOpCount(scriptSig) > 0) {
|
||||||
|
BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, scriptPubKey, flags | SCRIPT_VERIFY_FORKID, MutableTransactionSignatureChecker(&tx, 0), &err), "FORKID" + message);
|
||||||
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_HASHTYPE, std::string(ScriptErrorString(err)) + ": " + message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void static NegateSignatureS(std::vector<unsigned char>& vchSig) {
|
void static NegateSignatureS(std::vector<unsigned char>& vchSig) {
|
||||||
|
@ -787,7 +798,7 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
|
||||||
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
|
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
|
||||||
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, MutableTransactionSignatureChecker(&txTo23, 0), &err));
|
||||||
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
|
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(script_combineSigs)
|
BOOST_AUTO_TEST_CASE(script_combineSigs)
|
||||||
{
|
{
|
||||||
|
|
|
@ -169,7 +169,7 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
|
||||||
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
|
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
|
||||||
const vector<unsigned char> &vchCryptedSecret)
|
const vector<unsigned char> &vchCryptedSecret)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
|
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
|
||||||
return false;
|
return false;
|
||||||
if (!fFileBacked)
|
if (!fFileBacked)
|
||||||
|
@ -477,7 +477,7 @@ bool CWallet::Verify(const string& walletFile, string& warningString, string& er
|
||||||
} catch (const boost::filesystem::filesystem_error&) {
|
} catch (const boost::filesystem::filesystem_error&) {
|
||||||
// failure is ok (well, not really, but it's not worse than what we started with)
|
// failure is ok (well, not really, but it's not worse than what we started with)
|
||||||
}
|
}
|
||||||
|
|
||||||
// try again
|
// try again
|
||||||
if (!bitdb.Open(GetDataDir())) {
|
if (!bitdb.Open(GetDataDir())) {
|
||||||
// if it still fails, it probably means we can't even create the database env
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GetBoolArg("-salvagewallet", false))
|
if (GetBoolArg("-salvagewallet", false))
|
||||||
{
|
{
|
||||||
// Recover readable keypairs:
|
// Recover readable keypairs:
|
||||||
if (!CWalletDB::Recover(bitdb, walletFile, true))
|
if (!CWalletDB::Recover(bitdb, walletFile, true))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boost::filesystem::exists(GetDataDir() / walletFile))
|
if (boost::filesystem::exists(GetDataDir() / walletFile))
|
||||||
{
|
{
|
||||||
CDBEnv::VerifyResult r = bitdb.Verify(walletFile, CWalletDB::Recover);
|
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)
|
if (r == CDBEnv::RECOVER_FAIL)
|
||||||
errorString += _("wallet.dat corrupt, salvage failed");
|
errorString += _("wallet.dat corrupt, salvage failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2993,7 +2993,7 @@ bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark old keypool keys as used,
|
* Mark old keypool keys as used,
|
||||||
* and generate all new keys
|
* and generate all new keys
|
||||||
*/
|
*/
|
||||||
bool CWallet::NewKeyPool()
|
bool CWallet::NewKeyPool()
|
||||||
{
|
{
|
||||||
|
@ -3406,7 +3406,26 @@ public:
|
||||||
Process(script);
|
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 {
|
void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
|
||||||
|
|
Loading…
Reference in New Issue