Return the script type from Solver
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.
This commit is contained in:
parent
0a34593ddb
commit
984d72ec65
10 changed files with 62 additions and 98 deletions
|
@ -164,11 +164,11 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
|
||||||
insert(COutPoint(hash, i));
|
insert(COutPoint(hash, i));
|
||||||
else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
|
else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
|
||||||
{
|
{
|
||||||
txnouttype type;
|
|
||||||
std::vector<std::vector<unsigned char> > vSolutions;
|
std::vector<std::vector<unsigned char> > vSolutions;
|
||||||
if (Solver(txout.scriptPubKey, type, vSolutions) &&
|
txnouttype type = Solver(txout.scriptPubKey, vSolutions);
|
||||||
(type == TX_PUBKEY || type == TX_MULTISIG))
|
if (type == TX_PUBKEY || type == TX_MULTISIG) {
|
||||||
insert(COutPoint(hash, i));
|
insert(COutPoint(hash, i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,8 +141,7 @@ void ScriptToUniv(const CScript& script, UniValue& out, bool include_address)
|
||||||
out.pushKV("hex", HexStr(script.begin(), script.end()));
|
out.pushKV("hex", HexStr(script.begin(), script.end()));
|
||||||
|
|
||||||
std::vector<std::vector<unsigned char>> solns;
|
std::vector<std::vector<unsigned char>> solns;
|
||||||
txnouttype type;
|
txnouttype type = Solver(script, solns);
|
||||||
Solver(script, type, solns);
|
|
||||||
out.pushKV("type", GetTxnOutputType(type));
|
out.pushKV("type", GetTxnOutputType(type));
|
||||||
|
|
||||||
CTxDestination address;
|
CTxDestination address;
|
||||||
|
|
|
@ -57,11 +57,11 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
|
||||||
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
|
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
|
||||||
{
|
{
|
||||||
std::vector<std::vector<unsigned char> > vSolutions;
|
std::vector<std::vector<unsigned char> > vSolutions;
|
||||||
if (!Solver(scriptPubKey, whichType, vSolutions))
|
whichType = Solver(scriptPubKey, vSolutions);
|
||||||
return false;
|
|
||||||
|
|
||||||
if (whichType == TX_MULTISIG)
|
if (whichType == TX_NONSTANDARD || whichType == TX_WITNESS_UNKNOWN) {
|
||||||
{
|
return false;
|
||||||
|
} else if (whichType == TX_MULTISIG) {
|
||||||
unsigned char m = vSolutions.front()[0];
|
unsigned char m = vSolutions.front()[0];
|
||||||
unsigned char n = vSolutions.back()[0];
|
unsigned char n = vSolutions.back()[0];
|
||||||
// Support up to x-of-3 multisig txns as standard
|
// Support up to x-of-3 multisig txns as standard
|
||||||
|
@ -70,10 +70,11 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
|
||||||
if (m < 1 || m > n)
|
if (m < 1 || m > n)
|
||||||
return false;
|
return false;
|
||||||
} else if (whichType == TX_NULL_DATA &&
|
} else if (whichType == TX_NULL_DATA &&
|
||||||
(!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes))
|
(!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return whichType != TX_NONSTANDARD && whichType != TX_WITNESS_UNKNOWN;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsStandardTx(const CTransaction& tx, std::string& reason)
|
bool IsStandardTx(const CTransaction& tx, std::string& reason)
|
||||||
|
@ -166,14 +167,10 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
||||||
const CTxOut& prev = mapInputs.AccessCoin(tx.vin[i].prevout).out;
|
const CTxOut& prev = mapInputs.AccessCoin(tx.vin[i].prevout).out;
|
||||||
|
|
||||||
std::vector<std::vector<unsigned char> > vSolutions;
|
std::vector<std::vector<unsigned char> > vSolutions;
|
||||||
txnouttype whichType;
|
txnouttype whichType = Solver(prev.scriptPubKey, vSolutions);
|
||||||
// get the scriptPubKey corresponding to this input:
|
if (whichType == TX_NONSTANDARD) {
|
||||||
const CScript& prevScript = prev.scriptPubKey;
|
|
||||||
if (!Solver(prevScript, whichType, vSolutions))
|
|
||||||
return false;
|
return false;
|
||||||
|
} else if (whichType == TX_SCRIPTHASH) {
|
||||||
if (whichType == TX_SCRIPTHASH)
|
|
||||||
{
|
|
||||||
std::vector<std::vector<unsigned char> > stack;
|
std::vector<std::vector<unsigned char> > stack;
|
||||||
// convert the scriptSig into a stack, so we can inspect the redeemScript
|
// convert the scriptSig into a stack, so we can inspect the redeemScript
|
||||||
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE))
|
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE))
|
||||||
|
|
|
@ -627,9 +627,8 @@ static UniValue decodescript(const JSONRPCRequest& request)
|
||||||
// P2SH and witness programs cannot be wrapped in P2WSH, if this script
|
// P2SH and witness programs cannot be wrapped in P2WSH, if this script
|
||||||
// is a witness program, don't return addresses for a segwit programs.
|
// is a witness program, don't return addresses for a segwit programs.
|
||||||
if (type.get_str() == "pubkey" || type.get_str() == "pubkeyhash" || type.get_str() == "multisig" || type.get_str() == "nonstandard") {
|
if (type.get_str() == "pubkey" || type.get_str() == "pubkeyhash" || type.get_str() == "multisig" || type.get_str() == "nonstandard") {
|
||||||
txnouttype which_type;
|
|
||||||
std::vector<std::vector<unsigned char>> solutions_data;
|
std::vector<std::vector<unsigned char>> solutions_data;
|
||||||
Solver(script, which_type, solutions_data);
|
txnouttype which_type = Solver(script, solutions_data);
|
||||||
// Uncompressed pubkeys cannot be used with segwit checksigs.
|
// Uncompressed pubkeys cannot be used with segwit checksigs.
|
||||||
// If the script contains an uncompressed pubkey, skip encoding of a segwit program.
|
// If the script contains an uncompressed pubkey, skip encoding of a segwit program.
|
||||||
if ((which_type == TX_PUBKEY) || (which_type == TX_MULTISIG)) {
|
if ((which_type == TX_PUBKEY) || (which_type == TX_MULTISIG)) {
|
||||||
|
|
|
@ -60,8 +60,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
|
||||||
IsMineResult ret = IsMineResult::NO;
|
IsMineResult ret = IsMineResult::NO;
|
||||||
|
|
||||||
std::vector<valtype> vSolutions;
|
std::vector<valtype> vSolutions;
|
||||||
txnouttype whichType;
|
txnouttype whichType = Solver(scriptPubKey, vSolutions);
|
||||||
Solver(scriptPubKey, whichType, vSolutions);
|
|
||||||
|
|
||||||
CKeyID keyID;
|
CKeyID keyID;
|
||||||
switch (whichType)
|
switch (whichType)
|
||||||
|
|
|
@ -102,8 +102,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
|
||||||
std::vector<unsigned char> sig;
|
std::vector<unsigned char> sig;
|
||||||
|
|
||||||
std::vector<valtype> vSolutions;
|
std::vector<valtype> vSolutions;
|
||||||
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
|
whichTypeRet = Solver(scriptPubKey, vSolutions);
|
||||||
return false;
|
|
||||||
|
|
||||||
switch (whichTypeRet)
|
switch (whichTypeRet)
|
||||||
{
|
{
|
||||||
|
@ -314,9 +313,8 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get scripts
|
// Get scripts
|
||||||
txnouttype script_type;
|
|
||||||
std::vector<std::vector<unsigned char>> solutions;
|
std::vector<std::vector<unsigned char>> solutions;
|
||||||
Solver(txout.scriptPubKey, script_type, solutions);
|
txnouttype script_type = Solver(txout.scriptPubKey, solutions);
|
||||||
SigVersion sigversion = SigVersion::BASE;
|
SigVersion sigversion = SigVersion::BASE;
|
||||||
CScript next_script = txout.scriptPubKey;
|
CScript next_script = txout.scriptPubKey;
|
||||||
|
|
||||||
|
@ -327,7 +325,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
|
||||||
next_script = std::move(redeem_script);
|
next_script = std::move(redeem_script);
|
||||||
|
|
||||||
// Get redeemScript type
|
// Get redeemScript type
|
||||||
Solver(next_script, script_type, solutions);
|
script_type = Solver(next_script, solutions);
|
||||||
stack.script.pop_back();
|
stack.script.pop_back();
|
||||||
}
|
}
|
||||||
if (script_type == TX_WITNESS_V0_SCRIPTHASH && !stack.witness.empty() && !stack.witness.back().empty()) {
|
if (script_type == TX_WITNESS_V0_SCRIPTHASH && !stack.witness.empty() && !stack.witness.back().empty()) {
|
||||||
|
@ -337,7 +335,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
|
||||||
next_script = std::move(witness_script);
|
next_script = std::move(witness_script);
|
||||||
|
|
||||||
// Get witnessScript type
|
// Get witnessScript type
|
||||||
Solver(next_script, script_type, solutions);
|
script_type = Solver(next_script, solutions);
|
||||||
stack.witness.pop_back();
|
stack.witness.pop_back();
|
||||||
stack.script = std::move(stack.witness);
|
stack.script = std::move(stack.witness);
|
||||||
stack.witness.clear();
|
stack.witness.clear();
|
||||||
|
|
|
@ -87,7 +87,7 @@ static bool MatchMultisig(const CScript& script, unsigned int& required, std::ve
|
||||||
return (it + 1 == script.end());
|
return (it + 1 == script.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet)
|
txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet)
|
||||||
{
|
{
|
||||||
vSolutionsRet.clear();
|
vSolutionsRet.clear();
|
||||||
|
|
||||||
|
@ -95,33 +95,28 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
|
||||||
// it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
|
// it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
|
||||||
if (scriptPubKey.IsPayToScriptHash())
|
if (scriptPubKey.IsPayToScriptHash())
|
||||||
{
|
{
|
||||||
typeRet = TX_SCRIPTHASH;
|
|
||||||
std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
|
std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
|
||||||
vSolutionsRet.push_back(hashBytes);
|
vSolutionsRet.push_back(hashBytes);
|
||||||
return true;
|
return TX_SCRIPTHASH;
|
||||||
}
|
}
|
||||||
|
|
||||||
int witnessversion;
|
int witnessversion;
|
||||||
std::vector<unsigned char> witnessprogram;
|
std::vector<unsigned char> witnessprogram;
|
||||||
if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
|
if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
|
||||||
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) {
|
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) {
|
||||||
typeRet = TX_WITNESS_V0_KEYHASH;
|
|
||||||
vSolutionsRet.push_back(witnessprogram);
|
vSolutionsRet.push_back(witnessprogram);
|
||||||
return true;
|
return TX_WITNESS_V0_KEYHASH;
|
||||||
}
|
}
|
||||||
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
|
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
|
||||||
typeRet = TX_WITNESS_V0_SCRIPTHASH;
|
|
||||||
vSolutionsRet.push_back(witnessprogram);
|
vSolutionsRet.push_back(witnessprogram);
|
||||||
return true;
|
return TX_WITNESS_V0_SCRIPTHASH;
|
||||||
}
|
}
|
||||||
if (witnessversion != 0) {
|
if (witnessversion != 0) {
|
||||||
typeRet = TX_WITNESS_UNKNOWN;
|
|
||||||
vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion});
|
vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion});
|
||||||
vSolutionsRet.push_back(std::move(witnessprogram));
|
vSolutionsRet.push_back(std::move(witnessprogram));
|
||||||
return true;
|
return TX_WITNESS_UNKNOWN;
|
||||||
}
|
}
|
||||||
typeRet = TX_NONSTANDARD;
|
return TX_NONSTANDARD;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provably prunable, data-carrying output
|
// Provably prunable, data-carrying output
|
||||||
|
@ -130,47 +125,39 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::v
|
||||||
// byte passes the IsPushOnly() test we don't care what exactly is in the
|
// byte passes the IsPushOnly() test we don't care what exactly is in the
|
||||||
// script.
|
// script.
|
||||||
if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
|
if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
|
||||||
typeRet = TX_NULL_DATA;
|
return TX_NULL_DATA;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned char> data;
|
std::vector<unsigned char> data;
|
||||||
if (MatchPayToPubkey(scriptPubKey, data)) {
|
if (MatchPayToPubkey(scriptPubKey, data)) {
|
||||||
typeRet = TX_PUBKEY;
|
|
||||||
vSolutionsRet.push_back(std::move(data));
|
vSolutionsRet.push_back(std::move(data));
|
||||||
return true;
|
return TX_PUBKEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MatchPayToPubkeyHash(scriptPubKey, data)) {
|
if (MatchPayToPubkeyHash(scriptPubKey, data)) {
|
||||||
typeRet = TX_PUBKEYHASH;
|
|
||||||
vSolutionsRet.push_back(std::move(data));
|
vSolutionsRet.push_back(std::move(data));
|
||||||
return true;
|
return TX_PUBKEYHASH;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int required;
|
unsigned int required;
|
||||||
std::vector<std::vector<unsigned char>> keys;
|
std::vector<std::vector<unsigned char>> keys;
|
||||||
if (MatchMultisig(scriptPubKey, required, keys)) {
|
if (MatchMultisig(scriptPubKey, required, keys)) {
|
||||||
typeRet = TX_MULTISIG;
|
|
||||||
vSolutionsRet.push_back({static_cast<unsigned char>(required)}); // safe as required is in range 1..16
|
vSolutionsRet.push_back({static_cast<unsigned char>(required)}); // safe as required is in range 1..16
|
||||||
vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
|
vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end());
|
||||||
vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..16
|
vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..16
|
||||||
return true;
|
return TX_MULTISIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
vSolutionsRet.clear();
|
vSolutionsRet.clear();
|
||||||
typeRet = TX_NONSTANDARD;
|
return TX_NONSTANDARD;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
||||||
{
|
{
|
||||||
std::vector<valtype> vSolutions;
|
std::vector<valtype> vSolutions;
|
||||||
txnouttype whichType;
|
txnouttype whichType = Solver(scriptPubKey, vSolutions);
|
||||||
if (!Solver(scriptPubKey, whichType, vSolutions))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (whichType == TX_PUBKEY)
|
if (whichType == TX_PUBKEY) {
|
||||||
{
|
|
||||||
CPubKey pubKey(vSolutions[0]);
|
CPubKey pubKey(vSolutions[0]);
|
||||||
if (!pubKey.IsValid())
|
if (!pubKey.IsValid())
|
||||||
return false;
|
return false;
|
||||||
|
@ -212,11 +199,11 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
||||||
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet)
|
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet)
|
||||||
{
|
{
|
||||||
addressRet.clear();
|
addressRet.clear();
|
||||||
typeRet = TX_NONSTANDARD;
|
|
||||||
std::vector<valtype> vSolutions;
|
std::vector<valtype> vSolutions;
|
||||||
if (!Solver(scriptPubKey, typeRet, vSolutions))
|
typeRet = Solver(scriptPubKey, vSolutions);
|
||||||
|
if (typeRet == TX_NONSTANDARD) {
|
||||||
return false;
|
return false;
|
||||||
if (typeRet == TX_NULL_DATA){
|
} else if (typeRet == TX_NULL_DATA) {
|
||||||
// This is data, not addresses
|
// This is data, not addresses
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -324,14 +311,12 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
|
||||||
|
|
||||||
CScript GetScriptForWitness(const CScript& redeemscript)
|
CScript GetScriptForWitness(const CScript& redeemscript)
|
||||||
{
|
{
|
||||||
txnouttype typ;
|
|
||||||
std::vector<std::vector<unsigned char> > vSolutions;
|
std::vector<std::vector<unsigned char> > vSolutions;
|
||||||
if (Solver(redeemscript, typ, vSolutions)) {
|
txnouttype typ = Solver(redeemscript, vSolutions);
|
||||||
if (typ == TX_PUBKEY) {
|
if (typ == TX_PUBKEY) {
|
||||||
return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end())));
|
return GetScriptForDestination(WitnessV0KeyHash(Hash160(vSolutions[0].begin(), vSolutions[0].end())));
|
||||||
} else if (typ == TX_PUBKEYHASH) {
|
} else if (typ == TX_PUBKEYHASH) {
|
||||||
return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0]));
|
return GetScriptForDestination(WitnessV0KeyHash(vSolutions[0]));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return GetScriptForDestination(WitnessV0ScriptHash(redeemscript));
|
return GetScriptForDestination(WitnessV0ScriptHash(redeemscript));
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,11 +135,10 @@ const char* GetTxnOutputType(txnouttype t);
|
||||||
* script hash, for P2PKH it will contain the key hash, etc.
|
* script hash, for P2PKH it will contain the key hash, etc.
|
||||||
*
|
*
|
||||||
* @param[in] scriptPubKey Script to parse
|
* @param[in] scriptPubKey Script to parse
|
||||||
* @param[out] typeRet The script type
|
|
||||||
* @param[out] vSolutionsRet Vector of parsed pubkeys and hashes
|
* @param[out] vSolutionsRet Vector of parsed pubkeys and hashes
|
||||||
* @return True if script matches standard template
|
* @return The script type. TX_NONSTANDARD represents a failed solve.
|
||||||
*/
|
*/
|
||||||
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
|
txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a standard scriptPubKey for the destination address. Assigns result to
|
* Parse a standard scriptPubKey for the destination address. Assigns result to
|
||||||
|
|
|
@ -25,22 +25,19 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
|
||||||
}
|
}
|
||||||
|
|
||||||
CScript s;
|
CScript s;
|
||||||
txnouttype whichType;
|
|
||||||
std::vector<std::vector<unsigned char> > solutions;
|
std::vector<std::vector<unsigned char> > solutions;
|
||||||
|
|
||||||
// TX_PUBKEY
|
// TX_PUBKEY
|
||||||
s.clear();
|
s.clear();
|
||||||
s << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
|
s << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
|
||||||
BOOST_CHECK(Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_PUBKEY);
|
||||||
BOOST_CHECK_EQUAL(whichType, TX_PUBKEY);
|
|
||||||
BOOST_CHECK_EQUAL(solutions.size(), 1U);
|
BOOST_CHECK_EQUAL(solutions.size(), 1U);
|
||||||
BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0]));
|
BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0]));
|
||||||
|
|
||||||
// TX_PUBKEYHASH
|
// TX_PUBKEYHASH
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
|
s << OP_DUP << OP_HASH160 << ToByteVector(pubkeys[0].GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||||
BOOST_CHECK(Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_PUBKEYHASH);
|
||||||
BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH);
|
|
||||||
BOOST_CHECK_EQUAL(solutions.size(), 1U);
|
BOOST_CHECK_EQUAL(solutions.size(), 1U);
|
||||||
BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID()));
|
BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID()));
|
||||||
|
|
||||||
|
@ -48,8 +45,7 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
|
||||||
CScript redeemScript(s); // initialize with leftover P2PKH script
|
CScript redeemScript(s); // initialize with leftover P2PKH script
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
|
s << OP_HASH160 << ToByteVector(CScriptID(redeemScript)) << OP_EQUAL;
|
||||||
BOOST_CHECK(Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_SCRIPTHASH);
|
||||||
BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH);
|
|
||||||
BOOST_CHECK_EQUAL(solutions.size(), 1U);
|
BOOST_CHECK_EQUAL(solutions.size(), 1U);
|
||||||
BOOST_CHECK(solutions[0] == ToByteVector(CScriptID(redeemScript)));
|
BOOST_CHECK(solutions[0] == ToByteVector(CScriptID(redeemScript)));
|
||||||
|
|
||||||
|
@ -59,8 +55,7 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
|
||||||
ToByteVector(pubkeys[0]) <<
|
ToByteVector(pubkeys[0]) <<
|
||||||
ToByteVector(pubkeys[1]) <<
|
ToByteVector(pubkeys[1]) <<
|
||||||
OP_2 << OP_CHECKMULTISIG;
|
OP_2 << OP_CHECKMULTISIG;
|
||||||
BOOST_CHECK(Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_MULTISIG);
|
||||||
BOOST_CHECK_EQUAL(whichType, TX_MULTISIG);
|
|
||||||
BOOST_CHECK_EQUAL(solutions.size(), 4U);
|
BOOST_CHECK_EQUAL(solutions.size(), 4U);
|
||||||
BOOST_CHECK(solutions[0] == std::vector<unsigned char>({1}));
|
BOOST_CHECK(solutions[0] == std::vector<unsigned char>({1}));
|
||||||
BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0]));
|
BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0]));
|
||||||
|
@ -73,8 +68,7 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
|
||||||
ToByteVector(pubkeys[1]) <<
|
ToByteVector(pubkeys[1]) <<
|
||||||
ToByteVector(pubkeys[2]) <<
|
ToByteVector(pubkeys[2]) <<
|
||||||
OP_3 << OP_CHECKMULTISIG;
|
OP_3 << OP_CHECKMULTISIG;
|
||||||
BOOST_CHECK(Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_MULTISIG);
|
||||||
BOOST_CHECK_EQUAL(whichType, TX_MULTISIG);
|
|
||||||
BOOST_CHECK_EQUAL(solutions.size(), 5U);
|
BOOST_CHECK_EQUAL(solutions.size(), 5U);
|
||||||
BOOST_CHECK(solutions[0] == std::vector<unsigned char>({2}));
|
BOOST_CHECK(solutions[0] == std::vector<unsigned char>({2}));
|
||||||
BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0]));
|
BOOST_CHECK(solutions[1] == ToByteVector(pubkeys[0]));
|
||||||
|
@ -88,15 +82,13 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
|
||||||
std::vector<unsigned char>({0}) <<
|
std::vector<unsigned char>({0}) <<
|
||||||
std::vector<unsigned char>({75}) <<
|
std::vector<unsigned char>({75}) <<
|
||||||
std::vector<unsigned char>({255});
|
std::vector<unsigned char>({255});
|
||||||
BOOST_CHECK(Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NULL_DATA);
|
||||||
BOOST_CHECK_EQUAL(whichType, TX_NULL_DATA);
|
|
||||||
BOOST_CHECK_EQUAL(solutions.size(), 0U);
|
BOOST_CHECK_EQUAL(solutions.size(), 0U);
|
||||||
|
|
||||||
// TX_WITNESS_V0_KEYHASH
|
// TX_WITNESS_V0_KEYHASH
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_0 << ToByteVector(pubkeys[0].GetID());
|
s << OP_0 << ToByteVector(pubkeys[0].GetID());
|
||||||
BOOST_CHECK(Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_WITNESS_V0_KEYHASH);
|
||||||
BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_KEYHASH);
|
|
||||||
BOOST_CHECK_EQUAL(solutions.size(), 1U);
|
BOOST_CHECK_EQUAL(solutions.size(), 1U);
|
||||||
BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID()));
|
BOOST_CHECK(solutions[0] == ToByteVector(pubkeys[0].GetID()));
|
||||||
|
|
||||||
|
@ -107,16 +99,14 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
|
||||||
|
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_0 << ToByteVector(scriptHash);
|
s << OP_0 << ToByteVector(scriptHash);
|
||||||
BOOST_CHECK(Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_WITNESS_V0_SCRIPTHASH);
|
||||||
BOOST_CHECK_EQUAL(whichType, TX_WITNESS_V0_SCRIPTHASH);
|
|
||||||
BOOST_CHECK_EQUAL(solutions.size(), 1U);
|
BOOST_CHECK_EQUAL(solutions.size(), 1U);
|
||||||
BOOST_CHECK(solutions[0] == ToByteVector(scriptHash));
|
BOOST_CHECK(solutions[0] == ToByteVector(scriptHash));
|
||||||
|
|
||||||
// TX_NONSTANDARD
|
// TX_NONSTANDARD
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
|
s << OP_9 << OP_ADD << OP_11 << OP_EQUAL;
|
||||||
BOOST_CHECK(!Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
||||||
BOOST_CHECK_EQUAL(whichType, TX_NONSTANDARD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
|
BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
|
||||||
|
@ -127,53 +117,52 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
|
||||||
pubkey = key.GetPubKey();
|
pubkey = key.GetPubKey();
|
||||||
|
|
||||||
CScript s;
|
CScript s;
|
||||||
txnouttype whichType;
|
|
||||||
std::vector<std::vector<unsigned char> > solutions;
|
std::vector<std::vector<unsigned char> > solutions;
|
||||||
|
|
||||||
// TX_PUBKEY with incorrectly sized pubkey
|
// TX_PUBKEY with incorrectly sized pubkey
|
||||||
s.clear();
|
s.clear();
|
||||||
s << std::vector<unsigned char>(30, 0x01) << OP_CHECKSIG;
|
s << std::vector<unsigned char>(30, 0x01) << OP_CHECKSIG;
|
||||||
BOOST_CHECK(!Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
||||||
|
|
||||||
// TX_PUBKEYHASH with incorrectly sized key hash
|
// TX_PUBKEYHASH with incorrectly sized key hash
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_DUP << OP_HASH160 << ToByteVector(pubkey) << OP_EQUALVERIFY << OP_CHECKSIG;
|
s << OP_DUP << OP_HASH160 << ToByteVector(pubkey) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||||
BOOST_CHECK(!Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
||||||
|
|
||||||
// TX_SCRIPTHASH with incorrectly sized script hash
|
// TX_SCRIPTHASH with incorrectly sized script hash
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_HASH160 << std::vector<unsigned char>(21, 0x01) << OP_EQUAL;
|
s << OP_HASH160 << std::vector<unsigned char>(21, 0x01) << OP_EQUAL;
|
||||||
BOOST_CHECK(!Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
||||||
|
|
||||||
// TX_MULTISIG 0/2
|
// TX_MULTISIG 0/2
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_0 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
|
s << OP_0 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
|
||||||
BOOST_CHECK(!Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
||||||
|
|
||||||
// TX_MULTISIG 2/1
|
// TX_MULTISIG 2/1
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_2 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
|
s << OP_2 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
|
||||||
BOOST_CHECK(!Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
||||||
|
|
||||||
// TX_MULTISIG n = 2 with 1 pubkey
|
// TX_MULTISIG n = 2 with 1 pubkey
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_1 << ToByteVector(pubkey) << OP_2 << OP_CHECKMULTISIG;
|
s << OP_1 << ToByteVector(pubkey) << OP_2 << OP_CHECKMULTISIG;
|
||||||
BOOST_CHECK(!Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
||||||
|
|
||||||
// TX_MULTISIG n = 1 with 0 pubkeys
|
// TX_MULTISIG n = 1 with 0 pubkeys
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_1 << OP_1 << OP_CHECKMULTISIG;
|
s << OP_1 << OP_1 << OP_CHECKMULTISIG;
|
||||||
BOOST_CHECK(!Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
||||||
|
|
||||||
// TX_NULL_DATA with other opcodes
|
// TX_NULL_DATA with other opcodes
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_RETURN << std::vector<unsigned char>({75}) << OP_ADD;
|
s << OP_RETURN << std::vector<unsigned char>({75}) << OP_ADD;
|
||||||
BOOST_CHECK(!Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
||||||
|
|
||||||
// TX_WITNESS with incorrect program size
|
// TX_WITNESS with incorrect program size
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_0 << std::vector<unsigned char>(19, 0x01);
|
s << OP_0 << std::vector<unsigned char>(19, 0x01);
|
||||||
BOOST_CHECK(!Solver(s, whichType, solutions));
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
|
BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
|
||||||
|
|
|
@ -4021,9 +4021,8 @@ public:
|
||||||
void ProcessSubScript(const CScript& subscript, UniValue& obj, bool include_addresses = false) const
|
void ProcessSubScript(const CScript& subscript, UniValue& obj, bool include_addresses = false) const
|
||||||
{
|
{
|
||||||
// Always present: script type and redeemscript
|
// Always present: script type and redeemscript
|
||||||
txnouttype which_type;
|
|
||||||
std::vector<std::vector<unsigned char>> solutions_data;
|
std::vector<std::vector<unsigned char>> solutions_data;
|
||||||
Solver(subscript, which_type, solutions_data);
|
txnouttype which_type = Solver(subscript, solutions_data);
|
||||||
obj.pushKV("script", GetTxnOutputType(which_type));
|
obj.pushKV("script", GetTxnOutputType(which_type));
|
||||||
obj.pushKV("hex", HexStr(subscript.begin(), subscript.end()));
|
obj.pushKV("hex", HexStr(subscript.begin(), subscript.end()));
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue