Decode P2WSH and P2SH if data from prev tx is available on decodingawtransaction functions

This commit is contained in:
Pol Espinasa 2024-11-07 19:42:09 +01:00
parent 018e5fcc46
commit 43dbc696b9
No known key found for this signature in database
GPG key ID: 28470907B40BF26D
4 changed files with 64 additions and 2 deletions

View file

@ -201,23 +201,31 @@ void TxToUniv(const CTransaction& tx, const uint256& block_hash, UniValue& entry
o.pushKV("hex", HexStr(txin.scriptSig));
in.pushKV("scriptSig", std::move(o));
}
if (!tx.vin[i].scriptWitness.IsNull()) {
if (!txin.scriptWitness.IsNull()) {
UniValue txinwitness(UniValue::VARR);
for (const auto& item : tx.vin[i].scriptWitness.stack) {
txinwitness.push_back(HexStr(item));
}
in.pushKV("txinwitness", std::move(txinwitness));
}
if (have_undo) {
const Coin& prev_coin = txundo->vprevout[i];
const CTxOut& prev_txout = prev_coin.out;
amt_total_in += prev_txout.nValue;
std::pair<CScript, int> script = GetScriptForTransactionInput(prev_txout.scriptPubKey, txin);
UniValue redeemScript(UniValue::VOBJ);
ScriptToUniv(script.first, redeemScript, false, true);
if (script.second != -2) {
in.pushKV("redeemScript", std::move(redeemScript));
}
if (verbosity == TxVerbosity::SHOW_DETAILS_AND_PREVOUT) {
UniValue o_script_pub_key(UniValue::VOBJ);
ScriptToUniv(prev_txout.scriptPubKey, /*out=*/o_script_pub_key, /*include_hex=*/true, /*include_address=*/true);
UniValue p(UniValue::VOBJ);
p.pushKV("generated", bool(prev_coin.fCoinBase));
p.pushKV("height", uint64_t(prev_coin.nHeight));

View file

@ -119,6 +119,12 @@ static std::vector<RPCResult> DecodeTxDoc(const std::string& txid_field_doc)
{
{RPCResult::Type::STR_HEX, "hex", "hex-encoded witness data (if any)"},
}},
{RPCResult::Type::OBJ, "redeemScript", /*optional=*/true, "The decoded redeem script",
{
{RPCResult::Type::STR, "asm", "Human readable disassembly of the redeem script"},
{RPCResult::Type::STR, "desc", "Descriptor of the redeem script"},
{RPCResult::Type::STR, "type", "Type of the redeem script"},
}},
{RPCResult::Type::NUM, "sequence", "The script sequence number"},
}},
}},

View file

@ -10,9 +10,13 @@
#include <hash.h>
#include <uint256.h>
#include <util/hash_type.h>
#include<script/interpreter.h>
#include <string>
CScriptID::CScriptID(const CScript& in) : BaseHash(Hash160(in)) {}
std::string GetOpName(opcodetype opcode)
@ -387,3 +391,44 @@ bool CheckMinimalPush(const std::vector<unsigned char>& data, opcodetype opcode)
}
return true;
}
std::pair<CScript, int> GetScriptForTransactionInput(CScript prevScript, const CTxIn& txin)
{
bool p2sh = false;
if (prevScript.IsPayToScriptHash()) {
std::vector <std::vector<unsigned char> > stack;
if (!EvalScript(stack, txin.scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE)) {
return std::make_pair(CScript(), -2);
}
if (stack.empty()) {
return std::make_pair(CScript(), -2);
}
prevScript = CScript(stack.back().begin(), stack.back().end());
p2sh = true;
}
int witnessversion = 0;
std::vector<unsigned char> witnessprogram;
if (!prevScript.IsWitnessProgram(witnessversion, witnessprogram)) {
// For P2SH, scriptSig is always push-only, so the actual script is only the last stack item
// For non-P2SH, prevScript is likely the real script, but not part of this transaction, and scriptSig could very well be executable, so return the latter instead
return std::make_pair(p2sh ? prevScript : txin.scriptSig, -1);
}
Span stack{txin.scriptWitness.stack};
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
if (stack.empty()) return std::make_pair(CScript(), -2); // invalid
auto& script_data = stack.back();
prevScript = CScript(script_data.begin(), script_data.end());
return std::make_pair(prevScript, witnessversion);
}
if (witnessversion == 1 && witnessprogram.size() == WITNESS_V1_TAPROOT_SIZE && !p2sh) {
if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
SpanPopBack(stack);
}
if (stack.size() >= 2) {
SpanPopBack(stack); // Ignore control block
prevScript = CScript(stack.back().begin(), stack.back().end());
return std::make_pair(prevScript, witnessversion);
}
}
return std::make_pair(CScript(), -2);
}

View file

@ -581,6 +581,9 @@ public:
}
};
class CTxIn;
std::pair<CScript, int> GetScriptForTransactionInput(CScript prevScript, const CTxIn& txin);
struct CScriptWitness
{
// Note that this encodes the data elements being pushed, rather than