mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-05-22 18:05:19 +02:00
Merge #19114: scripted-diff: TxoutType C++11 scoped enum class
fa32adf9dc25540ad27f5b82654c7057d7738627 scripted-diff: TxoutType C++11 scoped enum class (MarcoFalke) fa95a694c492b267e4038674fd3f338dd215ab48 doc: Update outdated txnouttype documentation (MarcoFalke) fa58469c770d8c935a86462634e4e8cd806aa6e3 rpc: Properly use underlying type in GetAllOutputTypes (MarcoFalke) fa41c657022b8f99c8e6718a0e33c5838c412a0b rpc: Simplify GetAllOutputTypes with the Join helper (MarcoFalke) Pull request description: Non-scoped enums can accidentally and silently decay into an integral type. Also, the symbol names of the keys are exported to the surrounding (usually global) namespace. Fix both issues by switching to an `enum class TxoutType` in a (mostly) scripted-diff. ACKs for top commit: practicalswift: ACK fa32adf9dc25540ad27f5b82654c7057d7738627 -- patch looks correct hebasto: re-ACK fa32adf9dc25540ad27f5b82654c7057d7738627, since fa5997bd6fc82e16b597ea96e3c5c665f1f174ab (https://github.com/bitcoin/bitcoin/pull/19114#pullrequestreview-421425198) rebased only (verified with `git range-diff`). Tree-SHA512: f42a9db47f9be89fa4bdd8d2fb05a16726286d8b12e3d87327b67d723f91c7d5a57deb4b2ddae9e1d16fee7a5f8c00828b6dc8909c5db680fc5e0a3cf07cd465
This commit is contained in:
commit
d3a5dbfd1f
@ -135,8 +135,8 @@ bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx)
|
|||||||
else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
|
else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
|
||||||
{
|
{
|
||||||
std::vector<std::vector<unsigned char> > vSolutions;
|
std::vector<std::vector<unsigned char> > vSolutions;
|
||||||
txnouttype type = Solver(txout.scriptPubKey, vSolutions);
|
TxoutType type = Solver(txout.scriptPubKey, vSolutions);
|
||||||
if (type == TX_PUBKEY || type == TX_MULTISIG) {
|
if (type == TxoutType::PUBKEY || type == TxoutType::MULTISIG) {
|
||||||
insert(COutPoint(hash, i));
|
insert(COutPoint(hash, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,11 +140,11 @@ void ScriptToUniv(const CScript& script, UniValue& out, bool include_address)
|
|||||||
out.pushKV("hex", HexStr(script));
|
out.pushKV("hex", HexStr(script));
|
||||||
|
|
||||||
std::vector<std::vector<unsigned char>> solns;
|
std::vector<std::vector<unsigned char>> solns;
|
||||||
txnouttype type = Solver(script, solns);
|
TxoutType type = Solver(script, solns);
|
||||||
out.pushKV("type", GetTxnOutputType(type));
|
out.pushKV("type", GetTxnOutputType(type));
|
||||||
|
|
||||||
CTxDestination address;
|
CTxDestination address;
|
||||||
if (include_address && ExtractDestination(script, address) && type != TX_PUBKEY) {
|
if (include_address && ExtractDestination(script, address) && type != TxoutType::PUBKEY) {
|
||||||
out.pushKV("address", EncodeDestination(address));
|
out.pushKV("address", EncodeDestination(address));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,7 +152,7 @@ void ScriptToUniv(const CScript& script, UniValue& out, bool include_address)
|
|||||||
void ScriptPubKeyToUniv(const CScript& scriptPubKey,
|
void ScriptPubKeyToUniv(const CScript& scriptPubKey,
|
||||||
UniValue& out, bool fIncludeHex)
|
UniValue& out, bool fIncludeHex)
|
||||||
{
|
{
|
||||||
txnouttype type;
|
TxoutType type;
|
||||||
std::vector<CTxDestination> addresses;
|
std::vector<CTxDestination> addresses;
|
||||||
int nRequired;
|
int nRequired;
|
||||||
|
|
||||||
@ -160,7 +160,7 @@ void ScriptPubKeyToUniv(const CScript& scriptPubKey,
|
|||||||
if (fIncludeHex)
|
if (fIncludeHex)
|
||||||
out.pushKV("hex", HexStr(scriptPubKey));
|
out.pushKV("hex", HexStr(scriptPubKey));
|
||||||
|
|
||||||
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired) || type == TX_PUBKEY) {
|
if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired) || type == TxoutType::PUBKEY) {
|
||||||
out.pushKV("type", GetTxnOutputType(type));
|
out.pushKV("type", GetTxnOutputType(type));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -50,14 +50,14 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
|
|||||||
return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn));
|
return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
|
bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType)
|
||||||
{
|
{
|
||||||
std::vector<std::vector<unsigned char> > vSolutions;
|
std::vector<std::vector<unsigned char> > vSolutions;
|
||||||
whichType = Solver(scriptPubKey, vSolutions);
|
whichType = Solver(scriptPubKey, vSolutions);
|
||||||
|
|
||||||
if (whichType == TX_NONSTANDARD) {
|
if (whichType == TxoutType::NONSTANDARD) {
|
||||||
return false;
|
return false;
|
||||||
} else if (whichType == TX_MULTISIG) {
|
} else if (whichType == TxoutType::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
|
||||||
@ -65,7 +65,7 @@ bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
|
|||||||
return false;
|
return false;
|
||||||
if (m < 1 || m > n)
|
if (m < 1 || m > n)
|
||||||
return false;
|
return false;
|
||||||
} else if (whichType == TX_NULL_DATA &&
|
} else if (whichType == TxoutType::NULL_DATA &&
|
||||||
(!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) {
|
(!fAcceptDatacarrier || scriptPubKey.size() > nMaxDatacarrierBytes)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -110,16 +110,16 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned int nDataOut = 0;
|
unsigned int nDataOut = 0;
|
||||||
txnouttype whichType;
|
TxoutType whichType;
|
||||||
for (const CTxOut& txout : tx.vout) {
|
for (const CTxOut& txout : tx.vout) {
|
||||||
if (!::IsStandard(txout.scriptPubKey, whichType)) {
|
if (!::IsStandard(txout.scriptPubKey, whichType)) {
|
||||||
reason = "scriptpubkey";
|
reason = "scriptpubkey";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (whichType == TX_NULL_DATA)
|
if (whichType == TxoutType::NULL_DATA)
|
||||||
nDataOut++;
|
nDataOut++;
|
||||||
else if ((whichType == TX_MULTISIG) && (!permit_bare_multisig)) {
|
else if ((whichType == TxoutType::MULTISIG) && (!permit_bare_multisig)) {
|
||||||
reason = "bare-multisig";
|
reason = "bare-multisig";
|
||||||
return false;
|
return false;
|
||||||
} else if (IsDust(txout, dust_relay_fee)) {
|
} else if (IsDust(txout, dust_relay_fee)) {
|
||||||
@ -163,10 +163,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 = Solver(prev.scriptPubKey, vSolutions);
|
TxoutType whichType = Solver(prev.scriptPubKey, vSolutions);
|
||||||
if (whichType == TX_NONSTANDARD) {
|
if (whichType == TxoutType::NONSTANDARD) {
|
||||||
return false;
|
return false;
|
||||||
} else if (whichType == TX_SCRIPTHASH) {
|
} else if (whichType == TxoutType::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))
|
||||||
|
@ -81,7 +81,7 @@ CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee);
|
|||||||
|
|
||||||
bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee);
|
bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee);
|
||||||
|
|
||||||
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
|
bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType);
|
||||||
/**
|
/**
|
||||||
* Check for standard transaction types
|
* Check for standard transaction types
|
||||||
* @return True if all outputs (scriptPubKeys) use only standard transaction forms
|
* @return True if all outputs (scriptPubKeys) use only standard transaction forms
|
||||||
|
@ -511,12 +511,12 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request)
|
|||||||
|
|
||||||
static std::string GetAllOutputTypes()
|
static std::string GetAllOutputTypes()
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::vector<std::string> ret;
|
||||||
for (int i = TX_NONSTANDARD; i <= TX_WITNESS_UNKNOWN; ++i) {
|
using U = std::underlying_type<TxoutType>::type;
|
||||||
if (i != TX_NONSTANDARD) ret += ", ";
|
for (U i = (U)TxoutType::NONSTANDARD; i <= (U)TxoutType::WITNESS_UNKNOWN; ++i) {
|
||||||
ret += GetTxnOutputType(static_cast<txnouttype>(i));
|
ret.emplace_back(GetTxnOutputType(static_cast<TxoutType>(i)));
|
||||||
}
|
}
|
||||||
return ret;
|
return Join(ret, ", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
static UniValue decodescript(const JSONRPCRequest& request)
|
static UniValue decodescript(const JSONRPCRequest& request)
|
||||||
@ -580,10 +580,10 @@ static UniValue decodescript(const JSONRPCRequest& request)
|
|||||||
// 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") {
|
||||||
std::vector<std::vector<unsigned char>> solutions_data;
|
std::vector<std::vector<unsigned char>> solutions_data;
|
||||||
txnouttype which_type = Solver(script, solutions_data);
|
TxoutType 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 == TxoutType::PUBKEY) || (which_type == TxoutType::MULTISIG)) {
|
||||||
for (const auto& solution : solutions_data) {
|
for (const auto& solution : solutions_data) {
|
||||||
if ((solution.size() != 1) && !CPubKey(solution).IsCompressed()) {
|
if ((solution.size() != 1) && !CPubKey(solution).IsCompressed()) {
|
||||||
return r;
|
return r;
|
||||||
@ -592,9 +592,9 @@ static UniValue decodescript(const JSONRPCRequest& request)
|
|||||||
}
|
}
|
||||||
UniValue sr(UniValue::VOBJ);
|
UniValue sr(UniValue::VOBJ);
|
||||||
CScript segwitScr;
|
CScript segwitScr;
|
||||||
if (which_type == TX_PUBKEY) {
|
if (which_type == TxoutType::PUBKEY) {
|
||||||
segwitScr = GetScriptForDestination(WitnessV0KeyHash(Hash160(solutions_data[0].begin(), solutions_data[0].end())));
|
segwitScr = GetScriptForDestination(WitnessV0KeyHash(Hash160(solutions_data[0].begin(), solutions_data[0].end())));
|
||||||
} else if (which_type == TX_PUBKEYHASH) {
|
} else if (which_type == TxoutType::PUBKEYHASH) {
|
||||||
segwitScr = GetScriptForDestination(WitnessV0KeyHash(uint160{solutions_data[0]}));
|
segwitScr = GetScriptForDestination(WitnessV0KeyHash(uint160{solutions_data[0]}));
|
||||||
} else {
|
} else {
|
||||||
// Scripts that are not fit for P2WPKH are encoded as P2WSH.
|
// Scripts that are not fit for P2WPKH are encoded as P2WSH.
|
||||||
|
@ -985,15 +985,15 @@ std::unique_ptr<PubkeyProvider> InferPubkey(const CPubKey& pubkey, ParseScriptCo
|
|||||||
std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptContext ctx, const SigningProvider& provider)
|
std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptContext ctx, const SigningProvider& provider)
|
||||||
{
|
{
|
||||||
std::vector<std::vector<unsigned char>> data;
|
std::vector<std::vector<unsigned char>> data;
|
||||||
txnouttype txntype = Solver(script, data);
|
TxoutType txntype = Solver(script, data);
|
||||||
|
|
||||||
if (txntype == TX_PUBKEY) {
|
if (txntype == TxoutType::PUBKEY) {
|
||||||
CPubKey pubkey(data[0].begin(), data[0].end());
|
CPubKey pubkey(data[0].begin(), data[0].end());
|
||||||
if (pubkey.IsValid()) {
|
if (pubkey.IsValid()) {
|
||||||
return MakeUnique<PKDescriptor>(InferPubkey(pubkey, ctx, provider));
|
return MakeUnique<PKDescriptor>(InferPubkey(pubkey, ctx, provider));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (txntype == TX_PUBKEYHASH) {
|
if (txntype == TxoutType::PUBKEYHASH) {
|
||||||
uint160 hash(data[0]);
|
uint160 hash(data[0]);
|
||||||
CKeyID keyid(hash);
|
CKeyID keyid(hash);
|
||||||
CPubKey pubkey;
|
CPubKey pubkey;
|
||||||
@ -1001,7 +1001,7 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
|
|||||||
return MakeUnique<PKHDescriptor>(InferPubkey(pubkey, ctx, provider));
|
return MakeUnique<PKHDescriptor>(InferPubkey(pubkey, ctx, provider));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (txntype == TX_WITNESS_V0_KEYHASH && ctx != ParseScriptContext::P2WSH) {
|
if (txntype == TxoutType::WITNESS_V0_KEYHASH && ctx != ParseScriptContext::P2WSH) {
|
||||||
uint160 hash(data[0]);
|
uint160 hash(data[0]);
|
||||||
CKeyID keyid(hash);
|
CKeyID keyid(hash);
|
||||||
CPubKey pubkey;
|
CPubKey pubkey;
|
||||||
@ -1009,7 +1009,7 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
|
|||||||
return MakeUnique<WPKHDescriptor>(InferPubkey(pubkey, ctx, provider));
|
return MakeUnique<WPKHDescriptor>(InferPubkey(pubkey, ctx, provider));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (txntype == TX_MULTISIG) {
|
if (txntype == TxoutType::MULTISIG) {
|
||||||
std::vector<std::unique_ptr<PubkeyProvider>> providers;
|
std::vector<std::unique_ptr<PubkeyProvider>> providers;
|
||||||
for (size_t i = 1; i + 1 < data.size(); ++i) {
|
for (size_t i = 1; i + 1 < data.size(); ++i) {
|
||||||
CPubKey pubkey(data[i].begin(), data[i].end());
|
CPubKey pubkey(data[i].begin(), data[i].end());
|
||||||
@ -1017,7 +1017,7 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
|
|||||||
}
|
}
|
||||||
return MakeUnique<MultisigDescriptor>((int)data[0][0], std::move(providers));
|
return MakeUnique<MultisigDescriptor>((int)data[0][0], std::move(providers));
|
||||||
}
|
}
|
||||||
if (txntype == TX_SCRIPTHASH && ctx == ParseScriptContext::TOP) {
|
if (txntype == TxoutType::SCRIPTHASH && ctx == ParseScriptContext::TOP) {
|
||||||
uint160 hash(data[0]);
|
uint160 hash(data[0]);
|
||||||
CScriptID scriptid(hash);
|
CScriptID scriptid(hash);
|
||||||
CScript subscript;
|
CScript subscript;
|
||||||
@ -1026,7 +1026,7 @@ std::unique_ptr<DescriptorImpl> InferScript(const CScript& script, ParseScriptCo
|
|||||||
if (sub) return MakeUnique<SHDescriptor>(std::move(sub));
|
if (sub) return MakeUnique<SHDescriptor>(std::move(sub));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (txntype == TX_WITNESS_V0_SCRIPTHASH && ctx != ParseScriptContext::P2WSH) {
|
if (txntype == TxoutType::WITNESS_V0_SCRIPTHASH && ctx != ParseScriptContext::P2WSH) {
|
||||||
CScriptID scriptid;
|
CScriptID scriptid;
|
||||||
CRIPEMD160().Write(data[0].data(), data[0].size()).Finalize(scriptid.begin());
|
CRIPEMD160().Write(data[0].data(), data[0].size()).Finalize(scriptid.begin());
|
||||||
CScript subscript;
|
CScript subscript;
|
||||||
|
@ -92,11 +92,11 @@ static bool CreateSig(const BaseSignatureCreator& creator, SignatureData& sigdat
|
|||||||
/**
|
/**
|
||||||
* Sign scriptPubKey using signature made with creator.
|
* Sign scriptPubKey using signature made with creator.
|
||||||
* Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
|
* Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
|
||||||
* unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.
|
* unless whichTypeRet is TxoutType::SCRIPTHASH, in which case scriptSigRet is the redemption script.
|
||||||
* Returns false if scriptPubKey could not be completely satisfied.
|
* Returns false if scriptPubKey could not be completely satisfied.
|
||||||
*/
|
*/
|
||||||
static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& scriptPubKey,
|
static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator& creator, const CScript& scriptPubKey,
|
||||||
std::vector<valtype>& ret, txnouttype& whichTypeRet, SigVersion sigversion, SignatureData& sigdata)
|
std::vector<valtype>& ret, TxoutType& whichTypeRet, SigVersion sigversion, SignatureData& sigdata)
|
||||||
{
|
{
|
||||||
CScript scriptRet;
|
CScript scriptRet;
|
||||||
uint160 h160;
|
uint160 h160;
|
||||||
@ -108,15 +108,15 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
|
|||||||
|
|
||||||
switch (whichTypeRet)
|
switch (whichTypeRet)
|
||||||
{
|
{
|
||||||
case TX_NONSTANDARD:
|
case TxoutType::NONSTANDARD:
|
||||||
case TX_NULL_DATA:
|
case TxoutType::NULL_DATA:
|
||||||
case TX_WITNESS_UNKNOWN:
|
case TxoutType::WITNESS_UNKNOWN:
|
||||||
return false;
|
return false;
|
||||||
case TX_PUBKEY:
|
case TxoutType::PUBKEY:
|
||||||
if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]), scriptPubKey, sigversion)) return false;
|
if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]), scriptPubKey, sigversion)) return false;
|
||||||
ret.push_back(std::move(sig));
|
ret.push_back(std::move(sig));
|
||||||
return true;
|
return true;
|
||||||
case TX_PUBKEYHASH: {
|
case TxoutType::PUBKEYHASH: {
|
||||||
CKeyID keyID = CKeyID(uint160(vSolutions[0]));
|
CKeyID keyID = CKeyID(uint160(vSolutions[0]));
|
||||||
CPubKey pubkey;
|
CPubKey pubkey;
|
||||||
if (!GetPubKey(provider, sigdata, keyID, pubkey)) {
|
if (!GetPubKey(provider, sigdata, keyID, pubkey)) {
|
||||||
@ -129,7 +129,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
|
|||||||
ret.push_back(ToByteVector(pubkey));
|
ret.push_back(ToByteVector(pubkey));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case TX_SCRIPTHASH:
|
case TxoutType::SCRIPTHASH:
|
||||||
h160 = uint160(vSolutions[0]);
|
h160 = uint160(vSolutions[0]);
|
||||||
if (GetCScript(provider, sigdata, CScriptID{h160}, scriptRet)) {
|
if (GetCScript(provider, sigdata, CScriptID{h160}, scriptRet)) {
|
||||||
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
|
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
|
||||||
@ -139,7 +139,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
|
|||||||
sigdata.missing_redeem_script = h160;
|
sigdata.missing_redeem_script = h160;
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case TX_MULTISIG: {
|
case TxoutType::MULTISIG: {
|
||||||
size_t required = vSolutions.front()[0];
|
size_t required = vSolutions.front()[0];
|
||||||
ret.push_back(valtype()); // workaround CHECKMULTISIG bug
|
ret.push_back(valtype()); // workaround CHECKMULTISIG bug
|
||||||
for (size_t i = 1; i < vSolutions.size() - 1; ++i) {
|
for (size_t i = 1; i < vSolutions.size() - 1; ++i) {
|
||||||
@ -159,11 +159,11 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
|
|||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
case TX_WITNESS_V0_KEYHASH:
|
case TxoutType::WITNESS_V0_KEYHASH:
|
||||||
ret.push_back(vSolutions[0]);
|
ret.push_back(vSolutions[0]);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case TX_WITNESS_V0_SCRIPTHASH:
|
case TxoutType::WITNESS_V0_SCRIPTHASH:
|
||||||
CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin());
|
CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(h160.begin());
|
||||||
if (GetCScript(provider, sigdata, CScriptID{h160}, scriptRet)) {
|
if (GetCScript(provider, sigdata, CScriptID{h160}, scriptRet)) {
|
||||||
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
|
ret.push_back(std::vector<unsigned char>(scriptRet.begin(), scriptRet.end()));
|
||||||
@ -198,44 +198,44 @@ bool ProduceSignature(const SigningProvider& provider, const BaseSignatureCreato
|
|||||||
if (sigdata.complete) return true;
|
if (sigdata.complete) return true;
|
||||||
|
|
||||||
std::vector<valtype> result;
|
std::vector<valtype> result;
|
||||||
txnouttype whichType;
|
TxoutType whichType;
|
||||||
bool solved = SignStep(provider, creator, fromPubKey, result, whichType, SigVersion::BASE, sigdata);
|
bool solved = SignStep(provider, creator, fromPubKey, result, whichType, SigVersion::BASE, sigdata);
|
||||||
bool P2SH = false;
|
bool P2SH = false;
|
||||||
CScript subscript;
|
CScript subscript;
|
||||||
sigdata.scriptWitness.stack.clear();
|
sigdata.scriptWitness.stack.clear();
|
||||||
|
|
||||||
if (solved && whichType == TX_SCRIPTHASH)
|
if (solved && whichType == TxoutType::SCRIPTHASH)
|
||||||
{
|
{
|
||||||
// Solver returns the subscript that needs to be evaluated;
|
// Solver returns the subscript that needs to be evaluated;
|
||||||
// the final scriptSig is the signatures from that
|
// the final scriptSig is the signatures from that
|
||||||
// and then the serialized subscript:
|
// and then the serialized subscript:
|
||||||
subscript = CScript(result[0].begin(), result[0].end());
|
subscript = CScript(result[0].begin(), result[0].end());
|
||||||
sigdata.redeem_script = subscript;
|
sigdata.redeem_script = subscript;
|
||||||
solved = solved && SignStep(provider, creator, subscript, result, whichType, SigVersion::BASE, sigdata) && whichType != TX_SCRIPTHASH;
|
solved = solved && SignStep(provider, creator, subscript, result, whichType, SigVersion::BASE, sigdata) && whichType != TxoutType::SCRIPTHASH;
|
||||||
P2SH = true;
|
P2SH = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (solved && whichType == TX_WITNESS_V0_KEYHASH)
|
if (solved && whichType == TxoutType::WITNESS_V0_KEYHASH)
|
||||||
{
|
{
|
||||||
CScript witnessscript;
|
CScript witnessscript;
|
||||||
witnessscript << OP_DUP << OP_HASH160 << ToByteVector(result[0]) << OP_EQUALVERIFY << OP_CHECKSIG;
|
witnessscript << OP_DUP << OP_HASH160 << ToByteVector(result[0]) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||||
txnouttype subType;
|
TxoutType subType;
|
||||||
solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata);
|
solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata);
|
||||||
sigdata.scriptWitness.stack = result;
|
sigdata.scriptWitness.stack = result;
|
||||||
sigdata.witness = true;
|
sigdata.witness = true;
|
||||||
result.clear();
|
result.clear();
|
||||||
}
|
}
|
||||||
else if (solved && whichType == TX_WITNESS_V0_SCRIPTHASH)
|
else if (solved && whichType == TxoutType::WITNESS_V0_SCRIPTHASH)
|
||||||
{
|
{
|
||||||
CScript witnessscript(result[0].begin(), result[0].end());
|
CScript witnessscript(result[0].begin(), result[0].end());
|
||||||
sigdata.witness_script = witnessscript;
|
sigdata.witness_script = witnessscript;
|
||||||
txnouttype subType;
|
TxoutType subType;
|
||||||
solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata) && subType != TX_SCRIPTHASH && subType != TX_WITNESS_V0_SCRIPTHASH && subType != TX_WITNESS_V0_KEYHASH;
|
solved = solved && SignStep(provider, creator, witnessscript, result, subType, SigVersion::WITNESS_V0, sigdata) && subType != TxoutType::SCRIPTHASH && subType != TxoutType::WITNESS_V0_SCRIPTHASH && subType != TxoutType::WITNESS_V0_KEYHASH;
|
||||||
result.push_back(std::vector<unsigned char>(witnessscript.begin(), witnessscript.end()));
|
result.push_back(std::vector<unsigned char>(witnessscript.begin(), witnessscript.end()));
|
||||||
sigdata.scriptWitness.stack = result;
|
sigdata.scriptWitness.stack = result;
|
||||||
sigdata.witness = true;
|
sigdata.witness = true;
|
||||||
result.clear();
|
result.clear();
|
||||||
} else if (solved && whichType == TX_WITNESS_UNKNOWN) {
|
} else if (solved && whichType == TxoutType::WITNESS_UNKNOWN) {
|
||||||
sigdata.witness = true;
|
sigdata.witness = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,11 +301,11 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
|
|||||||
|
|
||||||
// Get scripts
|
// Get scripts
|
||||||
std::vector<std::vector<unsigned char>> solutions;
|
std::vector<std::vector<unsigned char>> solutions;
|
||||||
txnouttype script_type = Solver(txout.scriptPubKey, solutions);
|
TxoutType script_type = Solver(txout.scriptPubKey, solutions);
|
||||||
SigVersion sigversion = SigVersion::BASE;
|
SigVersion sigversion = SigVersion::BASE;
|
||||||
CScript next_script = txout.scriptPubKey;
|
CScript next_script = txout.scriptPubKey;
|
||||||
|
|
||||||
if (script_type == TX_SCRIPTHASH && !stack.script.empty() && !stack.script.back().empty()) {
|
if (script_type == TxoutType::SCRIPTHASH && !stack.script.empty() && !stack.script.back().empty()) {
|
||||||
// Get the redeemScript
|
// Get the redeemScript
|
||||||
CScript redeem_script(stack.script.back().begin(), stack.script.back().end());
|
CScript redeem_script(stack.script.back().begin(), stack.script.back().end());
|
||||||
data.redeem_script = redeem_script;
|
data.redeem_script = redeem_script;
|
||||||
@ -315,7 +315,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
|
|||||||
script_type = Solver(next_script, 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 == TxoutType::WITNESS_V0_SCRIPTHASH && !stack.witness.empty() && !stack.witness.back().empty()) {
|
||||||
// Get the witnessScript
|
// Get the witnessScript
|
||||||
CScript witness_script(stack.witness.back().begin(), stack.witness.back().end());
|
CScript witness_script(stack.witness.back().begin(), stack.witness.back().end());
|
||||||
data.witness_script = witness_script;
|
data.witness_script = witness_script;
|
||||||
@ -328,7 +328,7 @@ SignatureData DataFromTransaction(const CMutableTransaction& tx, unsigned int nI
|
|||||||
stack.witness.clear();
|
stack.witness.clear();
|
||||||
sigversion = SigVersion::WITNESS_V0;
|
sigversion = SigVersion::WITNESS_V0;
|
||||||
}
|
}
|
||||||
if (script_type == TX_MULTISIG && !stack.script.empty()) {
|
if (script_type == TxoutType::MULTISIG && !stack.script.empty()) {
|
||||||
// Build a map of pubkey -> signature by matching sigs to pubkeys:
|
// Build a map of pubkey -> signature by matching sigs to pubkeys:
|
||||||
assert(solutions.size() > 1);
|
assert(solutions.size() > 1);
|
||||||
unsigned int num_pubkeys = solutions.size()-2;
|
unsigned int num_pubkeys = solutions.size()-2;
|
||||||
@ -454,13 +454,13 @@ bool IsSegWitOutput(const SigningProvider& provider, const CScript& script)
|
|||||||
{
|
{
|
||||||
std::vector<valtype> solutions;
|
std::vector<valtype> solutions;
|
||||||
auto whichtype = Solver(script, solutions);
|
auto whichtype = Solver(script, solutions);
|
||||||
if (whichtype == TX_WITNESS_V0_SCRIPTHASH || whichtype == TX_WITNESS_V0_KEYHASH || whichtype == TX_WITNESS_UNKNOWN) return true;
|
if (whichtype == TxoutType::WITNESS_V0_SCRIPTHASH || whichtype == TxoutType::WITNESS_V0_KEYHASH || whichtype == TxoutType::WITNESS_UNKNOWN) return true;
|
||||||
if (whichtype == TX_SCRIPTHASH) {
|
if (whichtype == TxoutType::SCRIPTHASH) {
|
||||||
auto h160 = uint160(solutions[0]);
|
auto h160 = uint160(solutions[0]);
|
||||||
CScript subscript;
|
CScript subscript;
|
||||||
if (provider.GetCScript(CScriptID{h160}, subscript)) {
|
if (provider.GetCScript(CScriptID{h160}, subscript)) {
|
||||||
whichtype = Solver(subscript, solutions);
|
whichtype = Solver(subscript, solutions);
|
||||||
if (whichtype == TX_WITNESS_V0_SCRIPTHASH || whichtype == TX_WITNESS_V0_KEYHASH || whichtype == TX_WITNESS_UNKNOWN) return true;
|
if (whichtype == TxoutType::WITNESS_V0_SCRIPTHASH || whichtype == TxoutType::WITNESS_V0_KEYHASH || whichtype == TxoutType::WITNESS_UNKNOWN) return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -43,20 +43,20 @@ WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in)
|
|||||||
CSHA256().Write(in.data(), in.size()).Finalize(begin());
|
CSHA256().Write(in.data(), in.size()).Finalize(begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetTxnOutputType(txnouttype t)
|
std::string GetTxnOutputType(TxoutType t)
|
||||||
{
|
{
|
||||||
switch (t)
|
switch (t)
|
||||||
{
|
{
|
||||||
case TX_NONSTANDARD: return "nonstandard";
|
case TxoutType::NONSTANDARD: return "nonstandard";
|
||||||
case TX_PUBKEY: return "pubkey";
|
case TxoutType::PUBKEY: return "pubkey";
|
||||||
case TX_PUBKEYHASH: return "pubkeyhash";
|
case TxoutType::PUBKEYHASH: return "pubkeyhash";
|
||||||
case TX_SCRIPTHASH: return "scripthash";
|
case TxoutType::SCRIPTHASH: return "scripthash";
|
||||||
case TX_MULTISIG: return "multisig";
|
case TxoutType::MULTISIG: return "multisig";
|
||||||
case TX_NULL_DATA: return "nulldata";
|
case TxoutType::NULL_DATA: return "nulldata";
|
||||||
case TX_WITNESS_V0_KEYHASH: return "witness_v0_keyhash";
|
case TxoutType::WITNESS_V0_KEYHASH: return "witness_v0_keyhash";
|
||||||
case TX_WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash";
|
case TxoutType::WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash";
|
||||||
case TX_WITNESS_UNKNOWN: return "witness_unknown";
|
case TxoutType::WITNESS_UNKNOWN: return "witness_unknown";
|
||||||
}
|
} // no default case, so the compiler can warn about missing cases
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ static bool MatchMultisig(const CScript& script, unsigned int& required, std::ve
|
|||||||
return (it + 1 == script.end());
|
return (it + 1 == script.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet)
|
TxoutType Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet)
|
||||||
{
|
{
|
||||||
vSolutionsRet.clear();
|
vSolutionsRet.clear();
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned
|
|||||||
{
|
{
|
||||||
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 TX_SCRIPTHASH;
|
return TxoutType::SCRIPTHASH;
|
||||||
}
|
}
|
||||||
|
|
||||||
int witnessversion;
|
int witnessversion;
|
||||||
@ -124,18 +124,18 @@ txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned
|
|||||||
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) {
|
||||||
vSolutionsRet.push_back(witnessprogram);
|
vSolutionsRet.push_back(witnessprogram);
|
||||||
return TX_WITNESS_V0_KEYHASH;
|
return TxoutType::WITNESS_V0_KEYHASH;
|
||||||
}
|
}
|
||||||
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
|
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
|
||||||
vSolutionsRet.push_back(witnessprogram);
|
vSolutionsRet.push_back(witnessprogram);
|
||||||
return TX_WITNESS_V0_SCRIPTHASH;
|
return TxoutType::WITNESS_V0_SCRIPTHASH;
|
||||||
}
|
}
|
||||||
if (witnessversion != 0) {
|
if (witnessversion != 0) {
|
||||||
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 TX_WITNESS_UNKNOWN;
|
return TxoutType::WITNESS_UNKNOWN;
|
||||||
}
|
}
|
||||||
return TX_NONSTANDARD;
|
return TxoutType::NONSTANDARD;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provably prunable, data-carrying output
|
// Provably prunable, data-carrying output
|
||||||
@ -144,18 +144,18 @@ txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned
|
|||||||
// 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)) {
|
||||||
return TX_NULL_DATA;
|
return TxoutType::NULL_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<unsigned char> data;
|
std::vector<unsigned char> 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;
|
||||||
@ -164,19 +164,19 @@ txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned
|
|||||||
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 TX_MULTISIG;
|
return TxoutType::MULTISIG;
|
||||||
}
|
}
|
||||||
|
|
||||||
vSolutionsRet.clear();
|
vSolutionsRet.clear();
|
||||||
return TX_NONSTANDARD;
|
return TxoutType::NONSTANDARD;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
bool ExtractDestination(const CScript& scriptPubKey, 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;
|
||||||
@ -184,26 +184,26 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
|||||||
addressRet = PKHash(pubKey);
|
addressRet = PKHash(pubKey);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (whichType == TX_PUBKEYHASH)
|
else if (whichType == TxoutType::PUBKEYHASH)
|
||||||
{
|
{
|
||||||
addressRet = PKHash(uint160(vSolutions[0]));
|
addressRet = PKHash(uint160(vSolutions[0]));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (whichType == TX_SCRIPTHASH)
|
else if (whichType == TxoutType::SCRIPTHASH)
|
||||||
{
|
{
|
||||||
addressRet = ScriptHash(uint160(vSolutions[0]));
|
addressRet = ScriptHash(uint160(vSolutions[0]));
|
||||||
return true;
|
return true;
|
||||||
} else if (whichType == TX_WITNESS_V0_KEYHASH) {
|
} else if (whichType == TxoutType::WITNESS_V0_KEYHASH) {
|
||||||
WitnessV0KeyHash hash;
|
WitnessV0KeyHash hash;
|
||||||
std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
|
std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
|
||||||
addressRet = hash;
|
addressRet = hash;
|
||||||
return true;
|
return true;
|
||||||
} else if (whichType == TX_WITNESS_V0_SCRIPTHASH) {
|
} else if (whichType == TxoutType::WITNESS_V0_SCRIPTHASH) {
|
||||||
WitnessV0ScriptHash hash;
|
WitnessV0ScriptHash hash;
|
||||||
std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
|
std::copy(vSolutions[0].begin(), vSolutions[0].end(), hash.begin());
|
||||||
addressRet = hash;
|
addressRet = hash;
|
||||||
return true;
|
return true;
|
||||||
} else if (whichType == TX_WITNESS_UNKNOWN) {
|
} else if (whichType == TxoutType::WITNESS_UNKNOWN) {
|
||||||
WitnessUnknown unk;
|
WitnessUnknown unk;
|
||||||
unk.version = vSolutions[0][0];
|
unk.version = vSolutions[0][0];
|
||||||
std::copy(vSolutions[1].begin(), vSolutions[1].end(), unk.program);
|
std::copy(vSolutions[1].begin(), vSolutions[1].end(), unk.program);
|
||||||
@ -215,19 +215,19 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet)
|
bool ExtractDestinations(const CScript& scriptPubKey, TxoutType& typeRet, std::vector<CTxDestination>& addressRet, 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 (unsigned int i = 1; i < vSolutions.size()-1; i++)
|
for (unsigned int i = 1; i < vSolutions.size()-1; i++)
|
||||||
@ -319,10 +319,10 @@ CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
|
|||||||
CScript GetScriptForWitness(const CScript& redeemscript)
|
CScript GetScriptForWitness(const CScript& redeemscript)
|
||||||
{
|
{
|
||||||
std::vector<std::vector<unsigned char> > vSolutions;
|
std::vector<std::vector<unsigned char> > vSolutions;
|
||||||
txnouttype typ = Solver(redeemscript, vSolutions);
|
TxoutType typ = Solver(redeemscript, vSolutions);
|
||||||
if (typ == TX_PUBKEY) {
|
if (typ == TxoutType::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 == TxoutType::PUBKEYHASH) {
|
||||||
return GetScriptForDestination(WitnessV0KeyHash(uint160{vSolutions[0]}));
|
return GetScriptForDestination(WitnessV0KeyHash(uint160{vSolutions[0]}));
|
||||||
}
|
}
|
||||||
return GetScriptForDestination(WitnessV0ScriptHash(redeemscript));
|
return GetScriptForDestination(WitnessV0ScriptHash(redeemscript));
|
||||||
|
@ -99,11 +99,11 @@ static const unsigned int MAX_OP_RETURN_RELAY = 83;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A data carrying output is an unspendable output containing data. The script
|
* A data carrying output is an unspendable output containing data. The script
|
||||||
* type is designated as TX_NULL_DATA.
|
* type is designated as TxoutType::NULL_DATA.
|
||||||
*/
|
*/
|
||||||
extern bool fAcceptDatacarrier;
|
extern bool fAcceptDatacarrier;
|
||||||
|
|
||||||
/** Maximum size of TX_NULL_DATA scripts that this node considers standard. */
|
/** Maximum size of TxoutType::NULL_DATA scripts that this node considers standard. */
|
||||||
extern unsigned nMaxDatacarrierBytes;
|
extern unsigned nMaxDatacarrierBytes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -116,18 +116,17 @@ extern unsigned nMaxDatacarrierBytes;
|
|||||||
*/
|
*/
|
||||||
static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
|
static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
|
||||||
|
|
||||||
enum txnouttype
|
enum class TxoutType {
|
||||||
{
|
NONSTANDARD,
|
||||||
TX_NONSTANDARD,
|
|
||||||
// 'standard' transaction types:
|
// 'standard' transaction types:
|
||||||
TX_PUBKEY,
|
PUBKEY,
|
||||||
TX_PUBKEYHASH,
|
PUBKEYHASH,
|
||||||
TX_SCRIPTHASH,
|
SCRIPTHASH,
|
||||||
TX_MULTISIG,
|
MULTISIG,
|
||||||
TX_NULL_DATA, //!< unspendable OP_RETURN script that carries data
|
NULL_DATA, //!< unspendable OP_RETURN script that carries data
|
||||||
TX_WITNESS_V0_SCRIPTHASH,
|
WITNESS_V0_SCRIPTHASH,
|
||||||
TX_WITNESS_V0_KEYHASH,
|
WITNESS_V0_KEYHASH,
|
||||||
TX_WITNESS_UNKNOWN, //!< Only for Witness versions not already defined above
|
WITNESS_UNKNOWN, //!< Only for Witness versions not already defined above
|
||||||
};
|
};
|
||||||
|
|
||||||
class CNoDestination {
|
class CNoDestination {
|
||||||
@ -200,11 +199,11 @@ struct WitnessUnknown
|
|||||||
/**
|
/**
|
||||||
* 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
|
||||||
* * PKHash: TX_PUBKEYHASH destination (P2PKH)
|
* * PKHash: TxoutType::PUBKEYHASH destination (P2PKH)
|
||||||
* * ScriptHash: TX_SCRIPTHASH destination (P2SH)
|
* * ScriptHash: TxoutType::SCRIPTHASH destination (P2SH)
|
||||||
* * WitnessV0ScriptHash: TX_WITNESS_V0_SCRIPTHASH destination (P2WSH)
|
* * WitnessV0ScriptHash: TxoutType::WITNESS_V0_SCRIPTHASH destination (P2WSH)
|
||||||
* * WitnessV0KeyHash: TX_WITNESS_V0_KEYHASH destination (P2WPKH)
|
* * WitnessV0KeyHash: TxoutType::WITNESS_V0_KEYHASH destination (P2WPKH)
|
||||||
* * WitnessUnknown: TX_WITNESS_UNKNOWN destination (P2W???)
|
* * WitnessUnknown: TxoutType::WITNESS_UNKNOWN destination (P2W???)
|
||||||
* A CTxDestination is the internal data type encoded in a bitcoin address
|
* A CTxDestination is the internal data type encoded in a bitcoin address
|
||||||
*/
|
*/
|
||||||
typedef boost::variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown> CTxDestination;
|
typedef boost::variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown> CTxDestination;
|
||||||
@ -212,8 +211,8 @@ typedef boost::variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash,
|
|||||||
/** Check whether a CTxDestination is a CNoDestination. */
|
/** Check whether a CTxDestination is a CNoDestination. */
|
||||||
bool IsValidDestination(const CTxDestination& dest);
|
bool IsValidDestination(const CTxDestination& dest);
|
||||||
|
|
||||||
/** Get the name of a txnouttype as a C string, or nullptr if unknown. */
|
/** Get the name of a TxoutType as a string */
|
||||||
std::string GetTxnOutputType(txnouttype t);
|
std::string GetTxnOutputType(TxoutType t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a scriptPubKey and identify script type for standard scripts. If
|
* Parse a scriptPubKey and identify script type for standard scripts. If
|
||||||
@ -223,9 +222,9 @@ std::string GetTxnOutputType(txnouttype t);
|
|||||||
*
|
*
|
||||||
* @param[in] scriptPubKey Script to parse
|
* @param[in] scriptPubKey Script to parse
|
||||||
* @param[out] vSolutionsRet Vector of parsed pubkeys and hashes
|
* @param[out] vSolutionsRet Vector of parsed pubkeys and hashes
|
||||||
* @return The script type. TX_NONSTANDARD represents a failed solve.
|
* @return The script type. TxoutType::NONSTANDARD represents a failed solve.
|
||||||
*/
|
*/
|
||||||
txnouttype Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned char>>& vSolutionsRet);
|
TxoutType 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
|
||||||
@ -246,7 +245,7 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
|||||||
* encodable as an address) with key identifiers (of keys involved in a
|
* encodable as an address) with key identifiers (of keys involved in a
|
||||||
* CScript), and its use should be phased out.
|
* CScript), and its use should be phased out.
|
||||||
*/
|
*/
|
||||||
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
|
bool ExtractDestinations(const CScript& scriptPubKey, TxoutType& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a Bitcoin scriptPubKey for the given CTxDestination. Returns a P2PKH
|
* Generate a Bitcoin scriptPubKey for the given CTxDestination. Returns a P2PKH
|
||||||
|
@ -157,25 +157,25 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
|||||||
assert(ok_add_key_pubkey);
|
assert(ok_add_key_pubkey);
|
||||||
assert(fillable_signing_provider_pub.HaveKey(pubkey.GetID()));
|
assert(fillable_signing_provider_pub.HaveKey(pubkey.GetID()));
|
||||||
|
|
||||||
txnouttype which_type_tx_pubkey;
|
TxoutType which_type_tx_pubkey;
|
||||||
const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, which_type_tx_pubkey);
|
const bool is_standard_tx_pubkey = IsStandard(tx_pubkey_script, which_type_tx_pubkey);
|
||||||
assert(is_standard_tx_pubkey);
|
assert(is_standard_tx_pubkey);
|
||||||
assert(which_type_tx_pubkey == txnouttype::TX_PUBKEY);
|
assert(which_type_tx_pubkey == TxoutType::PUBKEY);
|
||||||
|
|
||||||
txnouttype which_type_tx_multisig;
|
TxoutType which_type_tx_multisig;
|
||||||
const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, which_type_tx_multisig);
|
const bool is_standard_tx_multisig = IsStandard(tx_multisig_script, which_type_tx_multisig);
|
||||||
assert(is_standard_tx_multisig);
|
assert(is_standard_tx_multisig);
|
||||||
assert(which_type_tx_multisig == txnouttype::TX_MULTISIG);
|
assert(which_type_tx_multisig == TxoutType::MULTISIG);
|
||||||
|
|
||||||
std::vector<std::vector<unsigned char>> v_solutions_ret_tx_pubkey;
|
std::vector<std::vector<unsigned char>> v_solutions_ret_tx_pubkey;
|
||||||
const txnouttype outtype_tx_pubkey = Solver(tx_pubkey_script, v_solutions_ret_tx_pubkey);
|
const TxoutType outtype_tx_pubkey = Solver(tx_pubkey_script, v_solutions_ret_tx_pubkey);
|
||||||
assert(outtype_tx_pubkey == txnouttype::TX_PUBKEY);
|
assert(outtype_tx_pubkey == TxoutType::PUBKEY);
|
||||||
assert(v_solutions_ret_tx_pubkey.size() == 1);
|
assert(v_solutions_ret_tx_pubkey.size() == 1);
|
||||||
assert(v_solutions_ret_tx_pubkey[0].size() == 33);
|
assert(v_solutions_ret_tx_pubkey[0].size() == 33);
|
||||||
|
|
||||||
std::vector<std::vector<unsigned char>> v_solutions_ret_tx_multisig;
|
std::vector<std::vector<unsigned char>> v_solutions_ret_tx_multisig;
|
||||||
const txnouttype outtype_tx_multisig = Solver(tx_multisig_script, v_solutions_ret_tx_multisig);
|
const TxoutType outtype_tx_multisig = Solver(tx_multisig_script, v_solutions_ret_tx_multisig);
|
||||||
assert(outtype_tx_multisig == txnouttype::TX_MULTISIG);
|
assert(outtype_tx_multisig == TxoutType::MULTISIG);
|
||||||
assert(v_solutions_ret_tx_multisig.size() == 3);
|
assert(v_solutions_ret_tx_multisig.size() == 3);
|
||||||
assert(v_solutions_ret_tx_multisig[0].size() == 1);
|
assert(v_solutions_ret_tx_multisig[0].size() == 1);
|
||||||
assert(v_solutions_ret_tx_multisig[1].size() == 33);
|
assert(v_solutions_ret_tx_multisig[1].size() == 33);
|
||||||
|
@ -58,7 +58,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
|||||||
CTxDestination address;
|
CTxDestination address;
|
||||||
(void)ExtractDestination(script, address);
|
(void)ExtractDestination(script, address);
|
||||||
|
|
||||||
txnouttype type_ret;
|
TxoutType type_ret;
|
||||||
std::vector<CTxDestination> addresses;
|
std::vector<CTxDestination> addresses;
|
||||||
int required_ret;
|
int required_ret;
|
||||||
(void)ExtractDestinations(script, type_ret, addresses, required_ret);
|
(void)ExtractDestinations(script, type_ret, addresses, required_ret);
|
||||||
@ -72,7 +72,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
|||||||
|
|
||||||
(void)IsSolvable(signing_provider, script);
|
(void)IsSolvable(signing_provider, script);
|
||||||
|
|
||||||
txnouttype which_type;
|
TxoutType which_type;
|
||||||
(void)IsStandard(script, which_type);
|
(void)IsStandard(script, which_type);
|
||||||
|
|
||||||
(void)RecursiveDynamicUsage(script);
|
(void)RecursiveDynamicUsage(script);
|
||||||
|
@ -141,7 +141,7 @@ BOOST_AUTO_TEST_CASE(multisig_IsStandard)
|
|||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
key[i].MakeNewKey(true);
|
key[i].MakeNewKey(true);
|
||||||
|
|
||||||
txnouttype whichType;
|
TxoutType whichType;
|
||||||
|
|
||||||
CScript a_and_b;
|
CScript a_and_b;
|
||||||
a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
|
a_and_b << OP_2 << ToByteVector(key[0].GetPubKey()) << ToByteVector(key[1].GetPubKey()) << OP_2 << OP_CHECKMULTISIG;
|
||||||
|
@ -31,35 +31,35 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
|
|||||||
CScript s;
|
CScript s;
|
||||||
std::vector<std::vector<unsigned char> > solutions;
|
std::vector<std::vector<unsigned char> > solutions;
|
||||||
|
|
||||||
// TX_PUBKEY
|
// TxoutType::PUBKEY
|
||||||
s.clear();
|
s.clear();
|
||||||
s << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
|
s << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
|
||||||
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_PUBKEY);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::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
|
// TxoutType::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_EQUAL(Solver(s, solutions), TX_PUBKEYHASH);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::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()));
|
||||||
|
|
||||||
// TX_SCRIPTHASH
|
// TxoutType::SCRIPTHASH
|
||||||
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_EQUAL(Solver(s, solutions), TX_SCRIPTHASH);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::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)));
|
||||||
|
|
||||||
// TX_MULTISIG
|
// TxoutType::MULTISIG
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_1 <<
|
s << OP_1 <<
|
||||||
ToByteVector(pubkeys[0]) <<
|
ToByteVector(pubkeys[0]) <<
|
||||||
ToByteVector(pubkeys[1]) <<
|
ToByteVector(pubkeys[1]) <<
|
||||||
OP_2 << OP_CHECKMULTISIG;
|
OP_2 << OP_CHECKMULTISIG;
|
||||||
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_MULTISIG);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::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]));
|
||||||
@ -72,7 +72,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_EQUAL(Solver(s, solutions), TX_MULTISIG);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::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]));
|
||||||
@ -80,37 +80,37 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_success)
|
|||||||
BOOST_CHECK(solutions[3] == ToByteVector(pubkeys[2]));
|
BOOST_CHECK(solutions[3] == ToByteVector(pubkeys[2]));
|
||||||
BOOST_CHECK(solutions[4] == std::vector<unsigned char>({3}));
|
BOOST_CHECK(solutions[4] == std::vector<unsigned char>({3}));
|
||||||
|
|
||||||
// TX_NULL_DATA
|
// TxoutType::NULL_DATA
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_RETURN <<
|
s << OP_RETURN <<
|
||||||
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_EQUAL(Solver(s, solutions), TX_NULL_DATA);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NULL_DATA);
|
||||||
BOOST_CHECK_EQUAL(solutions.size(), 0U);
|
BOOST_CHECK_EQUAL(solutions.size(), 0U);
|
||||||
|
|
||||||
// TX_WITNESS_V0_KEYHASH
|
// TxoutType::WITNESS_V0_KEYHASH
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_0 << ToByteVector(pubkeys[0].GetID());
|
s << OP_0 << ToByteVector(pubkeys[0].GetID());
|
||||||
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_WITNESS_V0_KEYHASH);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::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()));
|
||||||
|
|
||||||
// TX_WITNESS_V0_SCRIPTHASH
|
// TxoutType::WITNESS_V0_SCRIPTHASH
|
||||||
uint256 scriptHash;
|
uint256 scriptHash;
|
||||||
CSHA256().Write(&redeemScript[0], redeemScript.size())
|
CSHA256().Write(&redeemScript[0], redeemScript.size())
|
||||||
.Finalize(scriptHash.begin());
|
.Finalize(scriptHash.begin());
|
||||||
|
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_0 << ToByteVector(scriptHash);
|
s << OP_0 << ToByteVector(scriptHash);
|
||||||
BOOST_CHECK_EQUAL(Solver(s, solutions), TX_WITNESS_V0_SCRIPTHASH);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::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
|
// TxoutType::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_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
|
BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
|
||||||
@ -123,50 +123,50 @@ BOOST_AUTO_TEST_CASE(script_standard_Solver_failure)
|
|||||||
CScript s;
|
CScript s;
|
||||||
std::vector<std::vector<unsigned char> > solutions;
|
std::vector<std::vector<unsigned char> > solutions;
|
||||||
|
|
||||||
// TX_PUBKEY with incorrectly sized pubkey
|
// TxoutType::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_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD);
|
||||||
|
|
||||||
// TX_PUBKEYHASH with incorrectly sized key hash
|
// TxoutType::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_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD);
|
||||||
|
|
||||||
// TX_SCRIPTHASH with incorrectly sized script hash
|
// TxoutType::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_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD);
|
||||||
|
|
||||||
// TX_MULTISIG 0/2
|
// TxoutType::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_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD);
|
||||||
|
|
||||||
// TX_MULTISIG 2/1
|
// TxoutType::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_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD);
|
||||||
|
|
||||||
// TX_MULTISIG n = 2 with 1 pubkey
|
// TxoutType::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_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD);
|
||||||
|
|
||||||
// TX_MULTISIG n = 1 with 0 pubkeys
|
// TxoutType::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_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD);
|
||||||
|
|
||||||
// TX_NULL_DATA with other opcodes
|
// TxoutType::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_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD);
|
||||||
|
|
||||||
// TX_WITNESS with incorrect program size
|
// TxoutType::WITNESS_UNKNOWN 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_EQUAL(Solver(s, solutions), TX_NONSTANDARD);
|
BOOST_CHECK_EQUAL(Solver(s, solutions), TxoutType::NONSTANDARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
|
BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
|
||||||
@ -179,21 +179,21 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
|
|||||||
CScript s;
|
CScript s;
|
||||||
CTxDestination address;
|
CTxDestination address;
|
||||||
|
|
||||||
// TX_PUBKEY
|
// TxoutType::PUBKEY
|
||||||
s.clear();
|
s.clear();
|
||||||
s << ToByteVector(pubkey) << OP_CHECKSIG;
|
s << ToByteVector(pubkey) << OP_CHECKSIG;
|
||||||
BOOST_CHECK(ExtractDestination(s, address));
|
BOOST_CHECK(ExtractDestination(s, address));
|
||||||
BOOST_CHECK(boost::get<PKHash>(&address) &&
|
BOOST_CHECK(boost::get<PKHash>(&address) &&
|
||||||
*boost::get<PKHash>(&address) == PKHash(pubkey));
|
*boost::get<PKHash>(&address) == PKHash(pubkey));
|
||||||
|
|
||||||
// TX_PUBKEYHASH
|
// TxoutType::PUBKEYHASH
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
|
s << OP_DUP << OP_HASH160 << ToByteVector(pubkey.GetID()) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||||
BOOST_CHECK(ExtractDestination(s, address));
|
BOOST_CHECK(ExtractDestination(s, address));
|
||||||
BOOST_CHECK(boost::get<PKHash>(&address) &&
|
BOOST_CHECK(boost::get<PKHash>(&address) &&
|
||||||
*boost::get<PKHash>(&address) == PKHash(pubkey));
|
*boost::get<PKHash>(&address) == PKHash(pubkey));
|
||||||
|
|
||||||
// TX_SCRIPTHASH
|
// TxoutType::SCRIPTHASH
|
||||||
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;
|
||||||
@ -201,17 +201,17 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
|
|||||||
BOOST_CHECK(boost::get<ScriptHash>(&address) &&
|
BOOST_CHECK(boost::get<ScriptHash>(&address) &&
|
||||||
*boost::get<ScriptHash>(&address) == ScriptHash(redeemScript));
|
*boost::get<ScriptHash>(&address) == ScriptHash(redeemScript));
|
||||||
|
|
||||||
// TX_MULTISIG
|
// TxoutType::MULTISIG
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_1 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
|
s << OP_1 << ToByteVector(pubkey) << OP_1 << OP_CHECKMULTISIG;
|
||||||
BOOST_CHECK(!ExtractDestination(s, address));
|
BOOST_CHECK(!ExtractDestination(s, address));
|
||||||
|
|
||||||
// TX_NULL_DATA
|
// TxoutType::NULL_DATA
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_RETURN << std::vector<unsigned char>({75});
|
s << OP_RETURN << std::vector<unsigned char>({75});
|
||||||
BOOST_CHECK(!ExtractDestination(s, address));
|
BOOST_CHECK(!ExtractDestination(s, address));
|
||||||
|
|
||||||
// TX_WITNESS_V0_KEYHASH
|
// TxoutType::WITNESS_V0_KEYHASH
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_0 << ToByteVector(pubkey.GetID());
|
s << OP_0 << ToByteVector(pubkey.GetID());
|
||||||
BOOST_CHECK(ExtractDestination(s, address));
|
BOOST_CHECK(ExtractDestination(s, address));
|
||||||
@ -219,7 +219,7 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
|
|||||||
CHash160().Write(pubkey.begin(), pubkey.size()).Finalize(keyhash.begin());
|
CHash160().Write(pubkey.begin(), pubkey.size()).Finalize(keyhash.begin());
|
||||||
BOOST_CHECK(boost::get<WitnessV0KeyHash>(&address) && *boost::get<WitnessV0KeyHash>(&address) == keyhash);
|
BOOST_CHECK(boost::get<WitnessV0KeyHash>(&address) && *boost::get<WitnessV0KeyHash>(&address) == keyhash);
|
||||||
|
|
||||||
// TX_WITNESS_V0_SCRIPTHASH
|
// TxoutType::WITNESS_V0_SCRIPTHASH
|
||||||
s.clear();
|
s.clear();
|
||||||
WitnessV0ScriptHash scripthash;
|
WitnessV0ScriptHash scripthash;
|
||||||
CSHA256().Write(redeemScript.data(), redeemScript.size()).Finalize(scripthash.begin());
|
CSHA256().Write(redeemScript.data(), redeemScript.size()).Finalize(scripthash.begin());
|
||||||
@ -227,7 +227,7 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination)
|
|||||||
BOOST_CHECK(ExtractDestination(s, address));
|
BOOST_CHECK(ExtractDestination(s, address));
|
||||||
BOOST_CHECK(boost::get<WitnessV0ScriptHash>(&address) && *boost::get<WitnessV0ScriptHash>(&address) == scripthash);
|
BOOST_CHECK(boost::get<WitnessV0ScriptHash>(&address) && *boost::get<WitnessV0ScriptHash>(&address) == scripthash);
|
||||||
|
|
||||||
// TX_WITNESS with unknown version
|
// TxoutType::WITNESS_UNKNOWN with unknown version
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_1 << ToByteVector(pubkey);
|
s << OP_1 << ToByteVector(pubkey);
|
||||||
BOOST_CHECK(ExtractDestination(s, address));
|
BOOST_CHECK(ExtractDestination(s, address));
|
||||||
@ -248,49 +248,49 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
|
|||||||
}
|
}
|
||||||
|
|
||||||
CScript s;
|
CScript s;
|
||||||
txnouttype whichType;
|
TxoutType whichType;
|
||||||
std::vector<CTxDestination> addresses;
|
std::vector<CTxDestination> addresses;
|
||||||
int nRequired;
|
int nRequired;
|
||||||
|
|
||||||
// TX_PUBKEY
|
// TxoutType::PUBKEY
|
||||||
s.clear();
|
s.clear();
|
||||||
s << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
|
s << ToByteVector(pubkeys[0]) << OP_CHECKSIG;
|
||||||
BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
|
BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
|
||||||
BOOST_CHECK_EQUAL(whichType, TX_PUBKEY);
|
BOOST_CHECK_EQUAL(whichType, TxoutType::PUBKEY);
|
||||||
BOOST_CHECK_EQUAL(addresses.size(), 1U);
|
BOOST_CHECK_EQUAL(addresses.size(), 1U);
|
||||||
BOOST_CHECK_EQUAL(nRequired, 1);
|
BOOST_CHECK_EQUAL(nRequired, 1);
|
||||||
BOOST_CHECK(boost::get<PKHash>(&addresses[0]) &&
|
BOOST_CHECK(boost::get<PKHash>(&addresses[0]) &&
|
||||||
*boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
|
*boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
|
||||||
|
|
||||||
// TX_PUBKEYHASH
|
// TxoutType::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(ExtractDestinations(s, whichType, addresses, nRequired));
|
BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
|
||||||
BOOST_CHECK_EQUAL(whichType, TX_PUBKEYHASH);
|
BOOST_CHECK_EQUAL(whichType, TxoutType::PUBKEYHASH);
|
||||||
BOOST_CHECK_EQUAL(addresses.size(), 1U);
|
BOOST_CHECK_EQUAL(addresses.size(), 1U);
|
||||||
BOOST_CHECK_EQUAL(nRequired, 1);
|
BOOST_CHECK_EQUAL(nRequired, 1);
|
||||||
BOOST_CHECK(boost::get<PKHash>(&addresses[0]) &&
|
BOOST_CHECK(boost::get<PKHash>(&addresses[0]) &&
|
||||||
*boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
|
*boost::get<PKHash>(&addresses[0]) == PKHash(pubkeys[0]));
|
||||||
|
|
||||||
// TX_SCRIPTHASH
|
// TxoutType::SCRIPTHASH
|
||||||
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(ExtractDestinations(s, whichType, addresses, nRequired));
|
BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
|
||||||
BOOST_CHECK_EQUAL(whichType, TX_SCRIPTHASH);
|
BOOST_CHECK_EQUAL(whichType, TxoutType::SCRIPTHASH);
|
||||||
BOOST_CHECK_EQUAL(addresses.size(), 1U);
|
BOOST_CHECK_EQUAL(addresses.size(), 1U);
|
||||||
BOOST_CHECK_EQUAL(nRequired, 1);
|
BOOST_CHECK_EQUAL(nRequired, 1);
|
||||||
BOOST_CHECK(boost::get<ScriptHash>(&addresses[0]) &&
|
BOOST_CHECK(boost::get<ScriptHash>(&addresses[0]) &&
|
||||||
*boost::get<ScriptHash>(&addresses[0]) == ScriptHash(redeemScript));
|
*boost::get<ScriptHash>(&addresses[0]) == ScriptHash(redeemScript));
|
||||||
|
|
||||||
// TX_MULTISIG
|
// TxoutType::MULTISIG
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_2 <<
|
s << OP_2 <<
|
||||||
ToByteVector(pubkeys[0]) <<
|
ToByteVector(pubkeys[0]) <<
|
||||||
ToByteVector(pubkeys[1]) <<
|
ToByteVector(pubkeys[1]) <<
|
||||||
OP_2 << OP_CHECKMULTISIG;
|
OP_2 << OP_CHECKMULTISIG;
|
||||||
BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
|
BOOST_CHECK(ExtractDestinations(s, whichType, addresses, nRequired));
|
||||||
BOOST_CHECK_EQUAL(whichType, TX_MULTISIG);
|
BOOST_CHECK_EQUAL(whichType, TxoutType::MULTISIG);
|
||||||
BOOST_CHECK_EQUAL(addresses.size(), 2U);
|
BOOST_CHECK_EQUAL(addresses.size(), 2U);
|
||||||
BOOST_CHECK_EQUAL(nRequired, 2);
|
BOOST_CHECK_EQUAL(nRequired, 2);
|
||||||
BOOST_CHECK(boost::get<PKHash>(&addresses[0]) &&
|
BOOST_CHECK(boost::get<PKHash>(&addresses[0]) &&
|
||||||
@ -298,7 +298,7 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestinations)
|
|||||||
BOOST_CHECK(boost::get<PKHash>(&addresses[1]) &&
|
BOOST_CHECK(boost::get<PKHash>(&addresses[1]) &&
|
||||||
*boost::get<PKHash>(&addresses[1]) == PKHash(pubkeys[1]));
|
*boost::get<PKHash>(&addresses[1]) == PKHash(pubkeys[1]));
|
||||||
|
|
||||||
// TX_NULL_DATA
|
// TxoutType::NULL_DATA
|
||||||
s.clear();
|
s.clear();
|
||||||
s << OP_RETURN << std::vector<unsigned char>({75});
|
s << OP_RETURN << std::vector<unsigned char>({75});
|
||||||
BOOST_CHECK(!ExtractDestinations(s, whichType, addresses, nRequired));
|
BOOST_CHECK(!ExtractDestinations(s, whichType, addresses, nRequired));
|
||||||
|
@ -716,12 +716,12 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
|
|||||||
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
|
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
|
||||||
BOOST_CHECK_EQUAL(reason, "scriptpubkey");
|
BOOST_CHECK_EQUAL(reason, "scriptpubkey");
|
||||||
|
|
||||||
// MAX_OP_RETURN_RELAY-byte TX_NULL_DATA (standard)
|
// MAX_OP_RETURN_RELAY-byte TxoutType::NULL_DATA (standard)
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
|
||||||
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size());
|
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY, t.vout[0].scriptPubKey.size());
|
||||||
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
|
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
|
||||||
|
|
||||||
// MAX_OP_RETURN_RELAY+1-byte TX_NULL_DATA (non-standard)
|
// MAX_OP_RETURN_RELAY+1-byte TxoutType::NULL_DATA (non-standard)
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3804678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800");
|
||||||
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size());
|
BOOST_CHECK_EQUAL(MAX_OP_RETURN_RELAY + 1, t.vout[0].scriptPubKey.size());
|
||||||
reason.clear();
|
reason.clear();
|
||||||
@ -745,12 +745,12 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
|
|||||||
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
|
BOOST_CHECK(!IsStandardTx(CTransaction(t), reason));
|
||||||
BOOST_CHECK_EQUAL(reason, "scriptpubkey");
|
BOOST_CHECK_EQUAL(reason, "scriptpubkey");
|
||||||
|
|
||||||
// TX_NULL_DATA w/o PUSHDATA
|
// TxoutType::NULL_DATA w/o PUSHDATA
|
||||||
t.vout.resize(1);
|
t.vout.resize(1);
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN;
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN;
|
||||||
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
|
BOOST_CHECK(IsStandardTx(CTransaction(t), reason));
|
||||||
|
|
||||||
// Only one TX_NULL_DATA permitted in all cases
|
// Only one TxoutType::NULL_DATA permitted in all cases
|
||||||
t.vout.resize(2);
|
t.vout.resize(2);
|
||||||
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
|
t.vout[0].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
|
||||||
t.vout[1].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
|
t.vout[1].scriptPubKey = CScript() << OP_RETURN << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38");
|
||||||
|
@ -22,8 +22,8 @@ CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey, int n
|
|||||||
CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CScriptWitness& scriptWitness, const CTransaction& txCredit);
|
CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CScriptWitness& scriptWitness, const CTransaction& txCredit);
|
||||||
|
|
||||||
// Helper: create two dummy transactions, each with two outputs.
|
// Helper: create two dummy transactions, each with two outputs.
|
||||||
// The first has nValues[0] and nValues[1] outputs paid to a TX_PUBKEY,
|
// The first has nValues[0] and nValues[1] outputs paid to a TxoutType::PUBKEY,
|
||||||
// the second nValues[2] and nValues[3] outputs paid to a TX_PUBKEYHASH.
|
// the second nValues[2] and nValues[3] outputs paid to a TxoutType::PUBKEYHASH.
|
||||||
std::vector<CMutableTransaction> SetupDummyInputs(FillableSigningProvider& keystoreRet, CCoinsViewCache& coinsRet, const std::array<CAmount,4>& nValues);
|
std::vector<CMutableTransaction> SetupDummyInputs(FillableSigningProvider& keystoreRet, CCoinsViewCache& coinsRet, const std::array<CAmount,4>& nValues);
|
||||||
|
|
||||||
#endif // BITCOIN_TEST_UTIL_TRANSACTION_UTILS_H
|
#endif // BITCOIN_TEST_UTIL_TRANSACTION_UTILS_H
|
||||||
|
@ -856,20 +856,20 @@ static std::string RecurseImportData(const CScript& script, ImportData& import_d
|
|||||||
{
|
{
|
||||||
// Use Solver to obtain script type and parsed pubkeys or hashes:
|
// Use Solver to obtain script type and parsed pubkeys or hashes:
|
||||||
std::vector<std::vector<unsigned char>> solverdata;
|
std::vector<std::vector<unsigned char>> solverdata;
|
||||||
txnouttype script_type = Solver(script, solverdata);
|
TxoutType script_type = Solver(script, solverdata);
|
||||||
|
|
||||||
switch (script_type) {
|
switch (script_type) {
|
||||||
case TX_PUBKEY: {
|
case TxoutType::PUBKEY: {
|
||||||
CPubKey pubkey(solverdata[0].begin(), solverdata[0].end());
|
CPubKey pubkey(solverdata[0].begin(), solverdata[0].end());
|
||||||
import_data.used_keys.emplace(pubkey.GetID(), false);
|
import_data.used_keys.emplace(pubkey.GetID(), false);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
case TX_PUBKEYHASH: {
|
case TxoutType::PUBKEYHASH: {
|
||||||
CKeyID id = CKeyID(uint160(solverdata[0]));
|
CKeyID id = CKeyID(uint160(solverdata[0]));
|
||||||
import_data.used_keys[id] = true;
|
import_data.used_keys[id] = true;
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
case TX_SCRIPTHASH: {
|
case TxoutType::SCRIPTHASH: {
|
||||||
if (script_ctx == ScriptContext::P2SH) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2SH inside another P2SH");
|
if (script_ctx == ScriptContext::P2SH) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2SH inside another P2SH");
|
||||||
if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2SH inside a P2WSH");
|
if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2SH inside a P2WSH");
|
||||||
CHECK_NONFATAL(script_ctx == ScriptContext::TOP);
|
CHECK_NONFATAL(script_ctx == ScriptContext::TOP);
|
||||||
@ -880,14 +880,14 @@ static std::string RecurseImportData(const CScript& script, ImportData& import_d
|
|||||||
import_data.import_scripts.emplace(*subscript);
|
import_data.import_scripts.emplace(*subscript);
|
||||||
return RecurseImportData(*subscript, import_data, ScriptContext::P2SH);
|
return RecurseImportData(*subscript, import_data, ScriptContext::P2SH);
|
||||||
}
|
}
|
||||||
case TX_MULTISIG: {
|
case TxoutType::MULTISIG: {
|
||||||
for (size_t i = 1; i + 1< solverdata.size(); ++i) {
|
for (size_t i = 1; i + 1< solverdata.size(); ++i) {
|
||||||
CPubKey pubkey(solverdata[i].begin(), solverdata[i].end());
|
CPubKey pubkey(solverdata[i].begin(), solverdata[i].end());
|
||||||
import_data.used_keys.emplace(pubkey.GetID(), false);
|
import_data.used_keys.emplace(pubkey.GetID(), false);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
case TX_WITNESS_V0_SCRIPTHASH: {
|
case TxoutType::WITNESS_V0_SCRIPTHASH: {
|
||||||
if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2WSH inside another P2WSH");
|
if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2WSH inside another P2WSH");
|
||||||
uint256 fullid(solverdata[0]);
|
uint256 fullid(solverdata[0]);
|
||||||
CScriptID id;
|
CScriptID id;
|
||||||
@ -901,7 +901,7 @@ static std::string RecurseImportData(const CScript& script, ImportData& import_d
|
|||||||
import_data.import_scripts.emplace(*subscript);
|
import_data.import_scripts.emplace(*subscript);
|
||||||
return RecurseImportData(*subscript, import_data, ScriptContext::WITNESS_V0);
|
return RecurseImportData(*subscript, import_data, ScriptContext::WITNESS_V0);
|
||||||
}
|
}
|
||||||
case TX_WITNESS_V0_KEYHASH: {
|
case TxoutType::WITNESS_V0_KEYHASH: {
|
||||||
if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2WPKH inside P2WSH");
|
if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2WPKH inside P2WSH");
|
||||||
CKeyID id = CKeyID(uint160(solverdata[0]));
|
CKeyID id = CKeyID(uint160(solverdata[0]));
|
||||||
import_data.used_keys[id] = true;
|
import_data.used_keys[id] = true;
|
||||||
@ -910,10 +910,10 @@ static std::string RecurseImportData(const CScript& script, ImportData& import_d
|
|||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
case TX_NULL_DATA:
|
case TxoutType::NULL_DATA:
|
||||||
return "unspendable script";
|
return "unspendable script";
|
||||||
case TX_NONSTANDARD:
|
case TxoutType::NONSTANDARD:
|
||||||
case TX_WITNESS_UNKNOWN:
|
case TxoutType::WITNESS_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
return "unrecognized script";
|
return "unrecognized script";
|
||||||
}
|
}
|
||||||
|
@ -3503,7 +3503,7 @@ public:
|
|||||||
{
|
{
|
||||||
// Always present: script type and redeemscript
|
// Always present: script type and redeemscript
|
||||||
std::vector<std::vector<unsigned char>> solutions_data;
|
std::vector<std::vector<unsigned char>> solutions_data;
|
||||||
txnouttype which_type = Solver(subscript, solutions_data);
|
TxoutType which_type = Solver(subscript, solutions_data);
|
||||||
obj.pushKV("script", GetTxnOutputType(which_type));
|
obj.pushKV("script", GetTxnOutputType(which_type));
|
||||||
obj.pushKV("hex", HexStr(subscript));
|
obj.pushKV("hex", HexStr(subscript));
|
||||||
|
|
||||||
@ -3520,7 +3520,7 @@ public:
|
|||||||
// Always report the pubkey at the top level, so that `getnewaddress()['pubkey']` always works.
|
// Always report the pubkey at the top level, so that `getnewaddress()['pubkey']` always works.
|
||||||
if (subobj.exists("pubkey")) obj.pushKV("pubkey", subobj["pubkey"]);
|
if (subobj.exists("pubkey")) obj.pushKV("pubkey", subobj["pubkey"]);
|
||||||
obj.pushKV("embedded", std::move(subobj));
|
obj.pushKV("embedded", std::move(subobj));
|
||||||
} else if (which_type == TX_MULTISIG) {
|
} else if (which_type == TxoutType::MULTISIG) {
|
||||||
// Also report some information on multisig scripts (which do not have a corresponding address).
|
// Also report some information on multisig scripts (which do not have a corresponding address).
|
||||||
// TODO: abstract out the common functionality between this logic and ExtractDestinations.
|
// TODO: abstract out the common functionality between this logic and ExtractDestinations.
|
||||||
obj.pushKV("sigsrequired", solutions_data[0][0]);
|
obj.pushKV("sigsrequired", solutions_data[0][0]);
|
||||||
|
@ -88,16 +88,16 @@ IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& s
|
|||||||
IsMineResult ret = IsMineResult::NO;
|
IsMineResult ret = IsMineResult::NO;
|
||||||
|
|
||||||
std::vector<valtype> vSolutions;
|
std::vector<valtype> vSolutions;
|
||||||
txnouttype whichType = Solver(scriptPubKey, vSolutions);
|
TxoutType whichType = Solver(scriptPubKey, vSolutions);
|
||||||
|
|
||||||
CKeyID keyID;
|
CKeyID keyID;
|
||||||
switch (whichType)
|
switch (whichType)
|
||||||
{
|
{
|
||||||
case TX_NONSTANDARD:
|
case TxoutType::NONSTANDARD:
|
||||||
case TX_NULL_DATA:
|
case TxoutType::NULL_DATA:
|
||||||
case TX_WITNESS_UNKNOWN:
|
case TxoutType::WITNESS_UNKNOWN:
|
||||||
break;
|
break;
|
||||||
case TX_PUBKEY:
|
case TxoutType::PUBKEY:
|
||||||
keyID = CPubKey(vSolutions[0]).GetID();
|
keyID = CPubKey(vSolutions[0]).GetID();
|
||||||
if (!PermitsUncompressed(sigversion) && vSolutions[0].size() != 33) {
|
if (!PermitsUncompressed(sigversion) && vSolutions[0].size() != 33) {
|
||||||
return IsMineResult::INVALID;
|
return IsMineResult::INVALID;
|
||||||
@ -106,7 +106,7 @@ IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& s
|
|||||||
ret = std::max(ret, IsMineResult::SPENDABLE);
|
ret = std::max(ret, IsMineResult::SPENDABLE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TX_WITNESS_V0_KEYHASH:
|
case TxoutType::WITNESS_V0_KEYHASH:
|
||||||
{
|
{
|
||||||
if (sigversion == IsMineSigVersion::WITNESS_V0) {
|
if (sigversion == IsMineSigVersion::WITNESS_V0) {
|
||||||
// P2WPKH inside P2WSH is invalid.
|
// P2WPKH inside P2WSH is invalid.
|
||||||
@ -121,7 +121,7 @@ IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& s
|
|||||||
ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(PKHash(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0));
|
ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(PKHash(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TX_PUBKEYHASH:
|
case TxoutType::PUBKEYHASH:
|
||||||
keyID = CKeyID(uint160(vSolutions[0]));
|
keyID = CKeyID(uint160(vSolutions[0]));
|
||||||
if (!PermitsUncompressed(sigversion)) {
|
if (!PermitsUncompressed(sigversion)) {
|
||||||
CPubKey pubkey;
|
CPubKey pubkey;
|
||||||
@ -133,7 +133,7 @@ IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& s
|
|||||||
ret = std::max(ret, IsMineResult::SPENDABLE);
|
ret = std::max(ret, IsMineResult::SPENDABLE);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TX_SCRIPTHASH:
|
case TxoutType::SCRIPTHASH:
|
||||||
{
|
{
|
||||||
if (sigversion != IsMineSigVersion::TOP) {
|
if (sigversion != IsMineSigVersion::TOP) {
|
||||||
// P2SH inside P2WSH or P2SH is invalid.
|
// P2SH inside P2WSH or P2SH is invalid.
|
||||||
@ -146,7 +146,7 @@ IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& s
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TX_WITNESS_V0_SCRIPTHASH:
|
case TxoutType::WITNESS_V0_SCRIPTHASH:
|
||||||
{
|
{
|
||||||
if (sigversion == IsMineSigVersion::WITNESS_V0) {
|
if (sigversion == IsMineSigVersion::WITNESS_V0) {
|
||||||
// P2WSH inside P2WSH is invalid.
|
// P2WSH inside P2WSH is invalid.
|
||||||
@ -165,7 +165,7 @@ IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& s
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TX_MULTISIG:
|
case TxoutType::MULTISIG:
|
||||||
{
|
{
|
||||||
// Never treat bare multisig outputs as ours (they can still be made watchonly-though)
|
// Never treat bare multisig outputs as ours (they can still be made watchonly-though)
|
||||||
if (sigversion == IsMineSigVersion::TOP) {
|
if (sigversion == IsMineSigVersion::TOP) {
|
||||||
@ -836,7 +836,7 @@ bool LegacyScriptPubKeyMan::HaveWatchOnly() const
|
|||||||
static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut)
|
static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut)
|
||||||
{
|
{
|
||||||
std::vector<std::vector<unsigned char>> solutions;
|
std::vector<std::vector<unsigned char>> solutions;
|
||||||
return Solver(dest, solutions) == TX_PUBKEY &&
|
return Solver(dest, solutions) == TxoutType::PUBKEY &&
|
||||||
(pubKeyOut = CPubKey(solutions[0])).IsFullyValid();
|
(pubKeyOut = CPubKey(solutions[0])).IsFullyValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user