Skip to content

Commit

Permalink
Merge bitcoin#13429: Return the script type from Solver
Browse files Browse the repository at this point in the history
984d72e 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
  • Loading branch information
laanwj committed Aug 25, 2018
2 parents 776fa60 + 984d72e commit 4cef8e0
Show file tree
Hide file tree
Showing 10 changed files with 62 additions and 98 deletions.
6 changes: 3 additions & 3 deletions src/bloom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,11 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
insert(COutPoint(hash, i));
else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
{
txnouttype type;
std::vector<std::vector<unsigned char> > vSolutions;
if (Solver(txout.scriptPubKey, type, vSolutions) &&
(type == TX_PUBKEY || type == TX_MULTISIG))
txnouttype type = Solver(txout.scriptPubKey, vSolutions);
if (type == TX_PUBKEY || type == TX_MULTISIG) {
insert(COutPoint(hash, i));
}
}
break;
}
Expand Down
3 changes: 1 addition & 2 deletions src/core_write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,7 @@ void ScriptToUniv(const CScript& script, UniValue& out, bool include_address)
out.pushKV("hex", HexStr(script.begin(), script.end()));

std::vector<std::vector<unsigned char>> solns;
txnouttype type;
Solver(script, type, solns);
txnouttype type = Solver(script, solns);
out.pushKV("type", GetTxnOutputType(type));

CTxDestination address;
Expand Down
23 changes: 10 additions & 13 deletions src/policy/policy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
{
std::vector<std::vector<unsigned char> > vSolutions;
if (!Solver(scriptPubKey, whichType, vSolutions))
return false;
whichType = Solver(scriptPubKey, vSolutions);

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 n = vSolutions.back()[0];
// Support up to x-of-3 multisig txns as standard
Expand All @@ -70,10 +70,11 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
if (m < 1 || m > n)
return false;
} else if (whichType == TX_NULL_DATA &&
(!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes))
(!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) {
return false;
}

return whichType != TX_NONSTANDARD && whichType != TX_WITNESS_UNKNOWN;
return true;
}

bool IsStandardTx(const CTransaction& tx, std::string& reason)
Expand Down Expand Up @@ -166,14 +167,10 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
const CTxOut& prev = mapInputs.AccessCoin(tx.vin[i].prevout).out;

std::vector<std::vector<unsigned char> > vSolutions;
txnouttype whichType;
// get the scriptPubKey corresponding to this input:
const CScript& prevScript = prev.scriptPubKey;
if (!Solver(prevScript, whichType, vSolutions))
txnouttype whichType = Solver(prev.scriptPubKey, vSolutions);
if (whichType == TX_NONSTANDARD) {
return false;

if (whichType == TX_SCRIPTHASH)
{
} else if (whichType == TX_SCRIPTHASH) {
std::vector<std::vector<unsigned char> > stack;
// 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))
Expand Down
3 changes: 1 addition & 2 deletions src/rpc/rawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -626,9 +626,8 @@ static UniValue decodescript(const JSONRPCRequest& request)
// P2SH and witness programs cannot be wrapped in P2WSH, if this script
// 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") {
txnouttype which_type;
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.
// If the script contains an uncompressed pubkey, skip encoding of a segwit program.
if ((which_type == TX_PUBKEY) || (which_type == TX_MULTISIG)) {
Expand Down
3 changes: 1 addition & 2 deletions src/script/ismine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ IsMineResult IsMineInner(const CKeyStore& keystore, const CScript& scriptPubKey,
IsMineResult ret = IsMineResult::NO;

std::vector<valtype> vSolutions;
txnouttype whichType;
Solver(scriptPubKey, whichType, vSolutions);
txnouttype whichType = Solver(scriptPubKey, vSolutions);

CKeyID keyID;
switch (whichType)
Expand Down
10 changes: 4 additions & 6 deletions src/script/sign.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
std::vector<unsigned char> sig;

std::vector<valtype> vSolutions;
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
return false;
whichTypeRet = Solver(scriptPubKey, vSolutions);

switch (whichTypeRet)
{
Expand Down Expand Up @@ -329,9 +328,8 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
}

// Get scripts
txnouttype script_type;
std::vector<std::vector<unsigned char>> solutions;
Solver(txout.scriptPubKey, script_type, solutions);
txnouttype script_type = Solver(txout.scriptPubKey, solutions);
SigVersion sigversion = SigVersion::BASE;
CScript next_script = txout.scriptPubKey;

Expand All @@ -342,7 +340,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
next_script = std::move(redeem_script);

// Get redeemScript type
Solver(next_script, script_type, solutions);
script_type = Solver(next_script, solutions);
stack.script.pop_back();
}
if (script_type == TX_WITNESS_V0_SCRIPTHASH && !stack.witness.empty() && !stack.witness.back().empty()) {
Expand All @@ -352,7 +350,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
next_script = std::move(witness_script);

// Get witnessScript type
Solver(next_script, script_type, solutions);
script_type = Solver(next_script, solutions);
stack.witness.pop_back();
stack.script = std::move(stack.witness);
stack.witness.clear();
Expand Down
57 changes: 21 additions & 36 deletions src/script/standard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,41 +87,36 @@ static bool MatchMultisig(const CScript& script, unsigned int& required, std::ve
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();

// Shortcut for pay-to-script-hash, which are more constrained than the other types:
// it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
if (scriptPubKey.IsPayToScriptHash())
{
typeRet = TX_SCRIPTHASH;
std::vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
vSolutionsRet.push_back(hashBytes);
return true;
return TX_SCRIPTHASH;
}

int witnessversion;
std::vector<unsigned char> witnessprogram;
if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_KEYHASH_SIZE) {
typeRet = TX_WITNESS_V0_KEYHASH;
vSolutionsRet.push_back(witnessprogram);
return true;
return TX_WITNESS_V0_KEYHASH;
}
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
typeRet = TX_WITNESS_V0_SCRIPTHASH;
vSolutionsRet.push_back(witnessprogram);
return true;
return TX_WITNESS_V0_SCRIPTHASH;
}
if (witnessversion != 0) {
typeRet = TX_WITNESS_UNKNOWN;
vSolutionsRet.push_back(std::vector<unsigned char>{(unsigned char)witnessversion});
vSolutionsRet.push_back(std::move(witnessprogram));
return true;
return TX_WITNESS_UNKNOWN;
}
typeRet = TX_NONSTANDARD;
return false;
return TX_NONSTANDARD;
}

// Provably prunable, data-carrying output
Expand All @@ -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
// script.
if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
typeRet = TX_NULL_DATA;
return true;
return TX_NULL_DATA;
}

std::vector<unsigned char> data;
if (MatchPayToPubkey(scriptPubKey, data)) {
typeRet = TX_PUBKEY;
vSolutionsRet.push_back(std::move(data));
return true;
return TX_PUBKEY;
}

if (MatchPayToPubkeyHash(scriptPubKey, data)) {
typeRet = TX_PUBKEYHASH;
vSolutionsRet.push_back(std::move(data));
return true;
return TX_PUBKEYHASH;
}

unsigned int required;
std::vector<std::vector<unsigned char>> 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.insert(vSolutionsRet.end(), keys.begin(), keys.end());
vSolutionsRet.push_back({static_cast<unsigned char>(keys.size())}); // safe as size is in range 1..16
return true;
return TX_MULTISIG;
}

vSolutionsRet.clear();
typeRet = TX_NONSTANDARD;
return false;
return TX_NONSTANDARD;
}

bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
{
std::vector<valtype> vSolutions;
txnouttype whichType;
if (!Solver(scriptPubKey, whichType, vSolutions))
return false;
txnouttype whichType = Solver(scriptPubKey, vSolutions);

if (whichType == TX_PUBKEY)
{
if (whichType == TX_PUBKEY) {
CPubKey pubKey(vSolutions[0]);
if (!pubKey.IsValid())
return false;
Expand Down Expand Up @@ -212,11 +199,11 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet)
{
addressRet.clear();
typeRet = TX_NONSTANDARD;
std::vector<valtype> vSolutions;
if (!Solver(scriptPubKey, typeRet, vSolutions))
typeRet = Solver(scriptPubKey, vSolutions);
if (typeRet == TX_NONSTANDARD) {
return false;
if (typeRet == TX_NULL_DATA){
} else if (typeRet == TX_NULL_DATA) {
// This is data, not addresses
return false;
}
Expand Down Expand Up @@ -324,14 +311,12 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)

CScript GetScriptForWitness(const CScript& redeemscript)
{
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]));
}
txnouttype typ = Solver(redeemscript, 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]));
}
return GetScriptForDestination(WitnessV0ScriptHash(redeemscript));
}
Expand Down
5 changes: 2 additions & 3 deletions src/script/standard.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,10 @@ const char* GetTxnOutputType(txnouttype t);
* script hash, for P2PKH it will contain the key hash, etc.
*
* @param[in] scriptPubKey Script to parse
* @param[out] typeRet The script type
* @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
Expand Down
Loading

0 comments on commit 4cef8e0

Please sign in to comment.