bitcoin/src/test/script_standard_tests.cpp
Wladimir J. van der Laan 4cef8e0593
Merge #13429: Return the script type from Solver
984d72ec65 Return the script type from Solver (Ben Woosley)

Pull request description:

  Because false is synonymous with TX_NONSTANDARD, this conveys the same
  information and makes the handling explicitly based on script type,
  simplifying each call site.

  Prior to this change it was common for the return value to be ignored, or for the
  return value and TX_NONSTANDARD to be redundantly handled.

Tree-SHA512: 31864f856b8cb75f4b782d12678070e8b1cfe9665c6f57cfb25e7ac8bcea8a22f9a78d7c8cf0101c841f2a612400666fb91798bffe88de856e98b873703b0965
2018-08-25 17:41:00 +02:00

735 lines
24 KiB
C++

// Copyright (c) 2017-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <key.h>
#include <keystore.h>
#include <script/ismine.h>
#include <script/script.h>
#include <script/script_error.h>
#include <script/standard.h>
#include <test/test_bitcoin.h>
#include <boost/test/unit_test.hpp>
BOOST_FIXTURE_TEST_SUITE(script_standard_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
{
CKey keys[3];
CPubKey pubkeys[3];
for (int i = 0; i < 3; i++) {
keys[i].MakeNewKey(true);
pubkeys[i] = keys[i].GetPubKey();
}
CScript s;
std::vector<std::vector<unsigned char> > solutions;
// TX_PUBKEY
s.clear();
s << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_PUBKEY);
BOOST_CHECK_EQUAL(solutions.size(), 1U);
BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0]));
// TX_PUBKEYHASH
s.clear();
s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_PUBKEYHASH);
BOOST_CHECK_EQUAL(solutions.size(), 1U);
BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID()));
// TX_SCRIPTHASH
CScript redeemScript(s); // initialize with leftover P2PKH script
s.clear();
s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_SCRIPTHASH);
BOOST_CHECK_EQUAL(solutions.size(), 1U);
BOOST_CHECK(solutions[0] == ToByteVector(CScriptID(redeemScript)));
// TX_MULTISIG
s.clear();
s << OP_1 <<
ToByteVector(pubkeys[0]) <<
ToByteVector(pubkeys[1]) <<
OP_2 << OP_CHECKMULTISIG;
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_MULTISIG);
BOOST_CHECK_EQUAL(solutions.size(), 4U);
BOOST_CHECK(solutions[0] == std::vector<unsigned char>({1}));
BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0]));
BOOST_CHECK(solutions[2] == ToByteVector(pubkeys[1]));
BOOST_CHECK(solutions[3] == std::vector<unsigned char>({2}));
s.clear();
s << OP_2 <<
ToByteVector(pubkeys[0]) <<
ToByteVector(pubkeys[1]) <<
ToByteVector(pubkeys[2]) <<
OP_3 << OP_CHECKMULTISIG;
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_MULTISIG);
BOOST_CHECK_EQUAL(solutions.size(), 5U);
BOOST_CHECK(solutions[0] == std::vector<unsigned char>({2}));
BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0]));
BOOST_CHECK(solutions[2] == ToByteVector(pubkeys[1]));
BOOST_CHECK(solutions[3] == ToByteVector(pubkeys[2]));
BOOST_CHECK(solutions[4] == std::vector<unsigned char>({3}));
// TX_NULL_DATA
s.clear();
s << OP_RETURN <<
std::vector<unsigned char>({0}) <<
std::vector<unsigned char>({75}) <<
std::vector<unsigned char>({255});
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NULL_DATA);
BOOST_CHECK_EQUAL(solutions.size(), 0U);
// TX_WITNESS_V0_KEYHASH
s.clear();
s << OP_0 << ToByteVector(pubkeys[0].GetID());
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_WITNESS_V0_KEYHASH);
BOOST_CHECK_EQUAL(solutions.size(), 1U);
BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID()));
// TX_WITNESS_V0_SCRIPTHASH
uint256 scriptHash;
CSHA256().Write(&redeemScript[0], redeemScript.size())
.Finalize(scriptHash.begin());
s.clear();
s << OP_0 << ToByteVector(scriptHash);
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_WITNESS_V0_SCRIPTHASH);
BOOST_CHECK_EQUAL(solutions.size(), 1U);
BOOST_CHECK(solutions[0] == ToByteVector(scriptHash));
// TX_NONSTANDARD
s.clear();
s << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
}
BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
{
CKey key;
CPubKey pubkey;
key.MakeNewKey(true);
pubkey = key.GetPubKey();
CScript s;
std::vector<std::vector<unsigned char> > solutions;
// TX_PUBKEY with incorrectly sized pubkey
s.clear();
s << std::vector<unsigned char>(30, 0x01) << OP_CHECKSIG;
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_PUBKEYHASH with incorrectly sized key hash
s.clear();
s << OP_DUP << OP_HASH160 << ToByteVector(pubkey) << OP_EQUALVERIFY << OP_CHECKSIG;
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_SCRIPTHASH with incorrectly sized script hash
s.clear();
s << OP_HASH160 << std::vector<unsigned char>(21, 0x01) << OP_EQUAL;
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_MULTISIG 0/2
s.clear();
s << OP_0 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_MULTISIG 2/1
s.clear();
s << OP_2 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_MULTISIG n = 2 with 1 pubkey
s.clear();
s << OP_1 << ToByteVector(pubkey) << OP_2 << OP_CHECKMULTISIG;
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_MULTISIG n = 1 with 0 pubkeys
s.clear();
s << OP_1 << OP_1 << OP_CHECKMULTISIG;
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_NULL_DATA with other opcodes
s.clear();
s << OP_RETURN << std::vector<unsigned char>({75}) << OP_ADD;
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
// TX_WITNESS with incorrect program size
s.clear();
s << OP_0 << std::vector<unsigned char>(19, 0x01);
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
}
BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
{
CKey key;
CPubKey pubkey;
key.MakeNewKey(true);
pubkey = key.GetPubKey();
CScript s;
CTxDestination address;
// TX_PUBKEY
s.clear();
s << ToByteVector(pubkey) << OP_CHECKSIG;
BOOST_CHECK(ExtractDestination(s, address));
BOOST_CHECK(boost::get<CKeyID>(&address) &&
*boost::get<CKeyID>(&address) == pubkey.GetID());
// TX_PUBKEYHASH
s.clear();
s << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
BOOST_CHECK(ExtractDestination(s, address));
BOOST_CHECK(boost::get<CKeyID>(&address) &&
*boost::get<CKeyID>(&address) == pubkey.GetID());
// TX_SCRIPTHASH
CScript redeemScript(s); // initialize with leftover P2PKH script
s.clear();
s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
BOOST_CHECK(ExtractDestination(s, address));
BOOST_CHECK(boost::get<CScriptID>(&address) &&
*boost::get<CScriptID>(&address) == CScriptID(redeemScript));
// TX_MULTISIG
s.clear();
s << OP_1 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
BOOST_CHECK(!ExtractDestination(s, address));
// TX_NULL_DATA
s.clear();
s << OP_RETURN << std::vector<unsigned char>({75});
BOOST_CHECK(!ExtractDestination(s, address));
// TX_WITNESS_V0_KEYHASH
s.clear();
s << OP_0 << ToByteVector(pubkey.GetID());
BOOST_CHECK(ExtractDestination(s, address));
WitnessV0KeyHash keyhash;
CHash160().Write(pubkey.begin(), pubkey.size()).Finalize(keyhash.begin());
BOOST_CHECK(boost::get<WitnessV0KeyHash>(&address) && *boost::get<WitnessV0KeyHash>(&address) == keyhash);
// TX_WITNESS_V0_SCRIPTHASH
s.clear();
WitnessV0ScriptHash scripthash;
CSHA256().Write(redeemScript.data(), redeemScript.size()).Finalize(scripthash.begin());
s << OP_0 << ToByteVector(scripthash);
BOOST_CHECK(ExtractDestination(s, address));
BOOST_CHECK(boost::get<WitnessV0ScriptHash>(&address) && *boost::get<WitnessV0ScriptHash>(&address) == scripthash);
// TX_WITNESS with unknown version
s.clear();
s << OP_1 << ToByteVector(pubkey);
BOOST_CHECK(ExtractDestination(s, address));
WitnessUnknown unk;
unk.length = 33;
unk.version = 1;
std::copy(pubkey.begin(), pubkey.end(), unk.program);
BOOST_CHECK(boost::get<WitnessUnknown>(&address) && *boost::get<WitnessUnknown>(&address) == unk);
}
BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
{
CKey keys[3];
CPubKey pubkeys[3];
for (int i = 0; i < 3; i++) {
keys[i].MakeNewKey(true);
pubkeys[i] = keys[i].GetPubKey();
}
CScript s;
txnouttype whichType;
std::vector<CTxDestination> addresses;
int nRequired;
// TX_PUBKEY
s.clear();
s << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
BOOST_CHECK_EQUAL(whichType, TX_PUBKEY);
BOOST_CHECK_EQUAL(addresses.size(), 1U);
BOOST_CHECK_EQUAL(nRequired, 1);
BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) &&
*boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID());
// TX_PUBKEYHASH
s.clear();
s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH);
BOOST_CHECK_EQUAL(addresses.size(), 1U);
BOOST_CHECK_EQUAL(nRequired, 1);
BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) &&
*boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID());
// TX_SCRIPTHASH
CScript redeemScript(s); // initialize with leftover P2PKH script
s.clear();
s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH);
BOOST_CHECK_EQUAL(addresses.size(), 1U);
BOOST_CHECK_EQUAL(nRequired, 1);
BOOST_CHECK(boost::get<CScriptID>(&addresses[0]) &&
*boost::get<CScriptID>(&addresses[0]) == CScriptID(redeemScript));
// TX_MULTISIG
s.clear();
s << OP_2 <<
ToByteVector(pubkeys[0]) <<
ToByteVector(pubkeys[1]) <<
OP_2 << OP_CHECKMULTISIG;
BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
BOOST_CHECK_EQUAL(whichType, TX_MULTISIG);
BOOST_CHECK_EQUAL(addresses.size(), 2U);
BOOST_CHECK_EQUAL(nRequired, 2);
BOOST_CHECK(boost::get<CKeyID>(&addresses[0]) &&
*boost::get<CKeyID>(&addresses[0]) == pubkeys[0].GetID());
BOOST_CHECK(boost::get<CKeyID>(&addresses[1]) &&
*boost::get<CKeyID>(&addresses[1]) == pubkeys[1].GetID());
// TX_NULL_DATA
s.clear();
s << OP_RETURN << std::vector<unsigned char>({75});
BOOST_CHECK(!ExtractDestinations(s, whichType, addresses, nRequired));
}
BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_)
{
CKey keys[3];
CPubKey pubkeys[3];
for (int i = 0; i < 3; i++) {
keys[i].MakeNewKey(true);
pubkeys[i] = keys[i].GetPubKey();
}
CScript expected, result;
// CKeyID
expected.clear();
expected << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
result = GetScriptForDestination(pubkeys[0].GetID());
BOOST_CHECK(result == expected);
// CScriptID
CScript redeemScript(result);
expected.clear();
expected << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
result = GetScriptForDestination(CScriptID(redeemScript));
BOOST_CHECK(result == expected);
// CNoDestination
expected.clear();
result = GetScriptForDestination(CNoDestination());
BOOST_CHECK(result == expected);
// GetScriptForRawPubKey
expected.clear();
expected << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
result = GetScriptForRawPubKey(pubkeys[0]);
BOOST_CHECK(result == expected);
// GetScriptForMultisig
expected.clear();
expected << OP_2 <<
ToByteVector(pubkeys[0]) <<
ToByteVector(pubkeys[1]) <<
ToByteVector(pubkeys[2]) <<
OP_3 << OP_CHECKMULTISIG;
result = GetScriptForMultisig(2, std::vector<CPubKey>(pubkeys, pubkeys + 3));
BOOST_CHECK(result == expected);
// GetScriptForWitness
CScript witnessScript;
witnessScript << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
expected.clear();
expected << OP_0 << ToByteVector(pubkeys[0].GetID());
result = GetScriptForWitness(witnessScript);
BOOST_CHECK(result == expected);
witnessScript.clear();
witnessScript << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
result = GetScriptForWitness(witnessScript);
BOOST_CHECK(result == expected);
witnessScript.clear();
witnessScript << OP_1 << ToByteVector(pubkeys[0]) << OP_1 << OP_CHECKMULTISIG;
uint256 scriptHash;
CSHA256().Write(&witnessScript[0], witnessScript.size())
.Finalize(scriptHash.begin());
expected.clear();
expected << OP_0 << ToByteVector(scriptHash);
result = GetScriptForWitness(witnessScript);
BOOST_CHECK(result == expected);
}
BOOST_AUTO_TEST_CASE(script_standard_IsMine)
{
CKey keys[2];
CPubKey pubkeys[2];
for (int i = 0; i < 2; i++) {
keys[i].MakeNewKey(true);
pubkeys[i] = keys[i].GetPubKey();
}
CKey uncompressedKey;
uncompressedKey.MakeNewKey(false);
CPubKey uncompressedPubkey = uncompressedKey.GetPubKey();
CScript scriptPubKey;
isminetype result;
// P2PK compressed
{
CBasicKeyStore keystore;
scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
// Keystore does not have key
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has key
keystore.AddKey(keys[0]);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2PK uncompressed
{
CBasicKeyStore keystore;
scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
// Keystore does not have key
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has key
keystore.AddKey(uncompressedKey);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2PKH compressed
{
CBasicKeyStore keystore;
scriptPubKey = GetScriptForDestination(pubkeys[0].GetID());
// Keystore does not have key
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has key
keystore.AddKey(keys[0]);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2PKH uncompressed
{
CBasicKeyStore keystore;
scriptPubKey = GetScriptForDestination(uncompressedPubkey.GetID());
// Keystore does not have key
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has key
keystore.AddKey(uncompressedKey);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2SH
{
CBasicKeyStore keystore;
CScript redeemScript = GetScriptForDestination(pubkeys[0].GetID());
scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));
// Keystore does not have redeemScript or key
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has redeemScript but no key
keystore.AddCScript(redeemScript);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has redeemScript and key
keystore.AddKey(keys[0]);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// (P2PKH inside) P2SH inside P2SH (invalid)
{
CBasicKeyStore keystore;
CScript redeemscript_inner = GetScriptForDestination(pubkeys[0].GetID());
CScript redeemscript = GetScriptForDestination(CScriptID(redeemscript_inner));
scriptPubKey = GetScriptForDestination(CScriptID(redeemscript));
keystore.AddCScript(redeemscript);
keystore.AddCScript(redeemscript_inner);
keystore.AddCScript(scriptPubKey);
keystore.AddKey(keys[0]);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// (P2PKH inside) P2SH inside P2WSH (invalid)
{
CBasicKeyStore keystore;
CScript redeemscript = GetScriptForDestination(pubkeys[0].GetID());
CScript witnessscript = GetScriptForDestination(CScriptID(redeemscript));
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
keystore.AddCScript(witnessscript);
keystore.AddCScript(redeemscript);
keystore.AddCScript(scriptPubKey);
keystore.AddKey(keys[0]);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// P2WPKH inside P2WSH (invalid)
{
CBasicKeyStore keystore;
CScript witnessscript = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0].GetID()));
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
keystore.AddCScript(witnessscript);
keystore.AddCScript(scriptPubKey);
keystore.AddKey(keys[0]);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// (P2PKH inside) P2WSH inside P2WSH (invalid)
{
CBasicKeyStore keystore;
CScript witnessscript_inner = GetScriptForDestination(pubkeys[0].GetID());
CScript witnessscript = GetScriptForDestination(WitnessV0ScriptHash(witnessscript_inner));
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessscript));
keystore.AddCScript(witnessscript_inner);
keystore.AddCScript(witnessscript);
keystore.AddCScript(scriptPubKey);
keystore.AddKey(keys[0]);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// P2WPKH compressed
{
CBasicKeyStore keystore;
keystore.AddKey(keys[0]);
scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0].GetID()));
// Keystore implicitly has key and P2SH redeemScript
keystore.AddCScript(scriptPubKey);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2WPKH uncompressed
{
CBasicKeyStore keystore;
keystore.AddKey(uncompressedKey);
scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(uncompressedPubkey.GetID()));
// Keystore has key, but no P2SH redeemScript
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has key and P2SH redeemScript
keystore.AddCScript(scriptPubKey);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// scriptPubKey multisig
{
CBasicKeyStore keystore;
scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
// Keystore does not have any keys
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has 1/2 keys
keystore.AddKey(uncompressedKey);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has 2/2 keys
keystore.AddKey(keys[1]);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has 2/2 keys and the script
keystore.AddCScript(scriptPubKey);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// P2SH multisig
{
CBasicKeyStore keystore;
keystore.AddKey(uncompressedKey);
keystore.AddKey(keys[1]);
CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));
// Keystore has no redeemScript
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has redeemScript
keystore.AddCScript(redeemScript);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2WSH multisig with compressed keys
{
CBasicKeyStore keystore;
keystore.AddKey(keys[0]);
keystore.AddKey(keys[1]);
CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
// Keystore has keys, but no witnessScript or P2SH redeemScript
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has keys and witnessScript, but no P2SH redeemScript
keystore.AddCScript(witnessScript);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has keys, witnessScript, P2SH redeemScript
keystore.AddCScript(scriptPubKey);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// P2WSH multisig with uncompressed key
{
CBasicKeyStore keystore;
keystore.AddKey(uncompressedKey);
keystore.AddKey(keys[1]);
CScript witnessScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
// Keystore has keys, but no witnessScript or P2SH redeemScript
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has keys and witnessScript, but no P2SH redeemScript
keystore.AddCScript(witnessScript);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has keys, witnessScript, P2SH redeemScript
keystore.AddCScript(scriptPubKey);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// P2WSH multisig wrapped in P2SH
{
CBasicKeyStore keystore;
CScript witnessScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
scriptPubKey = GetScriptForDestination(CScriptID(redeemScript));
// Keystore has no witnessScript, P2SH redeemScript, or keys
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has witnessScript and P2SH redeemScript, but no keys
keystore.AddCScript(redeemScript);
keystore.AddCScript(witnessScript);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
// Keystore has keys, witnessScript, P2SH redeemScript
keystore.AddKey(keys[0]);
keystore.AddKey(keys[1]);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE);
}
// OP_RETURN
{
CBasicKeyStore keystore;
keystore.AddKey(keys[0]);
scriptPubKey.clear();
scriptPubKey << OP_RETURN << ToByteVector(pubkeys[0]);
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// witness unspendable
{
CBasicKeyStore keystore;
keystore.AddKey(keys[0]);
scriptPubKey.clear();
scriptPubKey << OP_0 << ToByteVector(ParseHex("aabb"));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// witness unknown
{
CBasicKeyStore keystore;
keystore.AddKey(keys[0]);
scriptPubKey.clear();
scriptPubKey << OP_16 << ToByteVector(ParseHex("aabb"));
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
// Nonstandard
{
CBasicKeyStore keystore;
keystore.AddKey(keys[0]);
scriptPubKey.clear();
scriptPubKey << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
result = IsMine(keystore, scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO);
}
}
BOOST_AUTO_TEST_SUITE_END()