Changeset View
Changeset View
Standalone View
Standalone View
src/script/standard.cpp
Show All 16 Lines | |||||
CScriptID::CScriptID(const CScript &in) | CScriptID::CScriptID(const CScript &in) | ||||
: uint160(Hash160(in.begin(), in.end())) {} | : uint160(Hash160(in.begin(), in.end())) {} | ||||
ScriptHash::ScriptHash(const CScript &in) | ScriptHash::ScriptHash(const CScript &in) | ||||
: uint160(Hash160(in.begin(), in.end())) {} | : uint160(Hash160(in.begin(), in.end())) {} | ||||
PKHash::PKHash(const CPubKey &pubkey) : uint160(pubkey.GetID()) {} | PKHash::PKHash(const CPubKey &pubkey) : uint160(pubkey.GetID()) {} | ||||
std::string GetTxnOutputType(txnouttype t) { | std::string GetTxnOutputType(TxoutType t) { | ||||
switch (t) { | switch (t) { | ||||
case TX_NONSTANDARD: | case TxoutType::NONSTANDARD: | ||||
return "nonstandard"; | return "nonstandard"; | ||||
case TX_PUBKEY: | case TxoutType::PUBKEY: | ||||
return "pubkey"; | return "pubkey"; | ||||
case TX_PUBKEYHASH: | case TxoutType::PUBKEYHASH: | ||||
return "pubkeyhash"; | return "pubkeyhash"; | ||||
case TX_SCRIPTHASH: | case TxoutType::SCRIPTHASH: | ||||
return "scripthash"; | return "scripthash"; | ||||
case TX_MULTISIG: | case TxoutType::MULTISIG: | ||||
return "multisig"; | return "multisig"; | ||||
case TX_NULL_DATA: | case TxoutType::NULL_DATA: | ||||
return "nulldata"; | return "nulldata"; | ||||
} | } // no default case, so the compiler can warn about missing cases | ||||
assert(false); | assert(false); | ||||
} | } | ||||
static bool MatchPayToPubkey(const CScript &script, valtype &pubkey) { | static bool MatchPayToPubkey(const CScript &script, valtype &pubkey) { | ||||
if (script.size() == CPubKey::SIZE + 2 && script[0] == CPubKey::SIZE && | if (script.size() == CPubKey::SIZE + 2 && script[0] == CPubKey::SIZE && | ||||
script.back() == OP_CHECKSIG) { | script.back() == OP_CHECKSIG) { | ||||
pubkey = | pubkey = | ||||
valtype(script.begin() + 1, script.begin() + CPubKey::SIZE + 1); | valtype(script.begin() + 1, script.begin() + CPubKey::SIZE + 1); | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | static bool MatchMultisig(const CScript &script, unsigned int &required, | ||||
} | } | ||||
unsigned int keys = CScript::DecodeOP_N(opcode); | unsigned int keys = CScript::DecodeOP_N(opcode); | ||||
if (pubkeys.size() != keys || keys < required) { | if (pubkeys.size() != keys || keys < required) { | ||||
return false; | return false; | ||||
} | } | ||||
return (it + 1 == script.end()); | return (it + 1 == script.end()); | ||||
} | } | ||||
txnouttype Solver(const CScript &scriptPubKey, | TxoutType Solver(const CScript &scriptPubKey, | ||||
std::vector<std::vector<uint8_t>> &vSolutionsRet) { | std::vector<std::vector<uint8_t>> &vSolutionsRet) { | ||||
vSolutionsRet.clear(); | vSolutionsRet.clear(); | ||||
// Shortcut for pay-to-script-hash, which are more constrained than the | // Shortcut for pay-to-script-hash, which are more constrained than the | ||||
// other types: | // other types: | ||||
// 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()) { | ||||
std::vector<uint8_t> hashBytes(scriptPubKey.begin() + 2, | std::vector<uint8_t> hashBytes(scriptPubKey.begin() + 2, | ||||
scriptPubKey.begin() + 22); | scriptPubKey.begin() + 22); | ||||
vSolutionsRet.push_back(hashBytes); | vSolutionsRet.push_back(hashBytes); | ||||
return TX_SCRIPTHASH; | return TxoutType::SCRIPTHASH; | ||||
} | } | ||||
// Provably prunable, data-carrying output | // Provably prunable, data-carrying output | ||||
// | // | ||||
// So long as script passes the IsUnspendable() test and all but the first | // So long as script passes the IsUnspendable() test and all but the first | ||||
// 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 && | if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && | ||||
scriptPubKey.IsPushOnly(scriptPubKey.begin() + 1)) { | scriptPubKey.IsPushOnly(scriptPubKey.begin() + 1)) { | ||||
return TX_NULL_DATA; | return TxoutType::NULL_DATA; | ||||
} | } | ||||
std::vector<uint8_t> data; | std::vector<uint8_t> data; | ||||
if (MatchPayToPubkey(scriptPubKey, data)) { | if (MatchPayToPubkey(scriptPubKey, data)) { | ||||
vSolutionsRet.push_back(std::move(data)); | vSolutionsRet.push_back(std::move(data)); | ||||
return TX_PUBKEY; | return TxoutType::PUBKEY; | ||||
} | } | ||||
if (MatchPayToPubkeyHash(scriptPubKey, data)) { | if (MatchPayToPubkeyHash(scriptPubKey, data)) { | ||||
vSolutionsRet.push_back(std::move(data)); | vSolutionsRet.push_back(std::move(data)); | ||||
return TX_PUBKEYHASH; | return TxoutType::PUBKEYHASH; | ||||
} | } | ||||
unsigned int required; | unsigned int required; | ||||
std::vector<std::vector<uint8_t>> keys; | std::vector<std::vector<uint8_t>> keys; | ||||
if (MatchMultisig(scriptPubKey, required, keys)) { | if (MatchMultisig(scriptPubKey, required, keys)) { | ||||
// safe as required is in range 1..16 | // safe as required is in range 1..16 | ||||
vSolutionsRet.push_back({static_cast<uint8_t>(required)}); | vSolutionsRet.push_back({static_cast<uint8_t>(required)}); | ||||
vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end()); | vSolutionsRet.insert(vSolutionsRet.end(), keys.begin(), keys.end()); | ||||
// safe as size is in range 1..16 | // safe as size is in range 1..16 | ||||
vSolutionsRet.push_back({static_cast<uint8_t>(keys.size())}); | vSolutionsRet.push_back({static_cast<uint8_t>(keys.size())}); | ||||
return TX_MULTISIG; | return TxoutType::MULTISIG; | ||||
} | } | ||||
vSolutionsRet.clear(); | vSolutionsRet.clear(); | ||||
return TX_NONSTANDARD; | return TxoutType::NONSTANDARD; | ||||
} | } | ||||
bool ExtractDestination(const CScript &scriptPubKey, | bool ExtractDestination(const CScript &scriptPubKey, | ||||
CTxDestination &addressRet) { | CTxDestination &addressRet) { | ||||
std::vector<valtype> vSolutions; | std::vector<valtype> vSolutions; | ||||
txnouttype whichType = Solver(scriptPubKey, vSolutions); | TxoutType whichType = Solver(scriptPubKey, vSolutions); | ||||
if (whichType == TX_PUBKEY) { | if (whichType == TxoutType::PUBKEY) { | ||||
CPubKey pubKey(vSolutions[0]); | CPubKey pubKey(vSolutions[0]); | ||||
if (!pubKey.IsValid()) { | if (!pubKey.IsValid()) { | ||||
return false; | return false; | ||||
} | } | ||||
addressRet = PKHash(pubKey); | addressRet = PKHash(pubKey); | ||||
return true; | return true; | ||||
} | } | ||||
if (whichType == TX_PUBKEYHASH) { | if (whichType == TxoutType::PUBKEYHASH) { | ||||
addressRet = PKHash(uint160(vSolutions[0])); | addressRet = PKHash(uint160(vSolutions[0])); | ||||
return true; | return true; | ||||
} | } | ||||
if (whichType == TX_SCRIPTHASH) { | if (whichType == TxoutType::SCRIPTHASH) { | ||||
addressRet = ScriptHash(uint160(vSolutions[0])); | addressRet = ScriptHash(uint160(vSolutions[0])); | ||||
return true; | return true; | ||||
} | } | ||||
// Multisig txns have more than one address... | // Multisig txns have more than one address... | ||||
return false; | return false; | ||||
} | } | ||||
bool ExtractDestinations(const CScript &scriptPubKey, txnouttype &typeRet, | bool ExtractDestinations(const CScript &scriptPubKey, TxoutType &typeRet, | ||||
std::vector<CTxDestination> &addressRet, | std::vector<CTxDestination> &addressRet, | ||||
int &nRequiredRet) { | int &nRequiredRet) { | ||||
addressRet.clear(); | addressRet.clear(); | ||||
std::vector<valtype> vSolutions; | std::vector<valtype> vSolutions; | ||||
typeRet = Solver(scriptPubKey, vSolutions); | typeRet = Solver(scriptPubKey, vSolutions); | ||||
if (typeRet == TX_NONSTANDARD) { | if (typeRet == TxoutType::NONSTANDARD) { | ||||
return false; | return false; | ||||
} else if (typeRet == TX_NULL_DATA) { | } else if (typeRet == TxoutType::NULL_DATA) { | ||||
// This is data, not addresses | // This is data, not addresses | ||||
return false; | return false; | ||||
} | } | ||||
if (typeRet == TX_MULTISIG) { | if (typeRet == TxoutType::MULTISIG) { | ||||
nRequiredRet = vSolutions.front()[0]; | nRequiredRet = vSolutions.front()[0]; | ||||
for (size_t i = 1; i < vSolutions.size() - 1; i++) { | for (size_t i = 1; i < vSolutions.size() - 1; i++) { | ||||
CPubKey pubKey(vSolutions[i]); | CPubKey pubKey(vSolutions[i]); | ||||
if (!pubKey.IsValid()) { | if (!pubKey.IsValid()) { | ||||
continue; | continue; | ||||
} | } | ||||
CTxDestination address = PKHash(pubKey); | CTxDestination address = PKHash(pubKey); | ||||
▲ Show 20 Lines • Show All 72 Lines • Show Last 20 Lines |