Skip to content

Commit c4f0ded

Browse files
committed
policy: GetScriptForTransactionInput to figure out P2SH, witness, taproot
Github-Pull: bitcoin#28408 Rebased-From: 62b0ebd
1 parent 938f427 commit c4f0ded

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

src/policy/policy.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,3 +372,50 @@ int64_t GetVirtualTransactionInputSize(const CTxIn& txin, int64_t nSigOpCost, un
372372
{
373373
return GetVirtualTransactionSize(GetTransactionInputWeight(txin), nSigOpCost, bytes_per_sigop);
374374
}
375+
376+
std::pair<CScript, unsigned int> GetScriptForTransactionInput(CScript prevScript, const CTxIn& txin)
377+
{
378+
bool p2sh = false;
379+
if (prevScript.IsPayToScriptHash()) {
380+
std::vector <std::vector<unsigned char> > stack;
381+
if (!EvalScript(stack, txin.scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE)) {
382+
return std::make_pair(CScript(), 0);
383+
}
384+
if (stack.empty()) {
385+
return std::make_pair(CScript(), 0);
386+
}
387+
prevScript = CScript(stack.back().begin(), stack.back().end());
388+
p2sh = true;
389+
}
390+
391+
int witnessversion = 0;
392+
std::vector<unsigned char> witnessprogram;
393+
394+
if (!prevScript.IsWitnessProgram(witnessversion, witnessprogram)) {
395+
// For P2SH, scriptSig is always push-only, so the actual script is only the last stack item
396+
// 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
397+
return std::make_pair(p2sh ? prevScript : txin.scriptSig, WITNESS_SCALE_FACTOR);
398+
}
399+
400+
Span stack{txin.scriptWitness.stack};
401+
402+
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
403+
if (stack.empty()) return std::make_pair(CScript(), 0); // invalid
404+
auto& script_data = stack.back();
405+
prevScript = CScript(script_data.begin(), script_data.end());
406+
return std::make_pair(prevScript, 1);
407+
}
408+
409+
if (witnessversion == 1 && witnessprogram.size() == WITNESS_V1_TAPROOT_SIZE && !p2sh) {
410+
if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
411+
SpanPopBack(stack);
412+
}
413+
if (stack.size() >= 2) {
414+
SpanPopBack(stack); // Ignore control block
415+
prevScript = CScript(stack.back().begin(), stack.back().end());
416+
return std::make_pair(prevScript, 1);
417+
}
418+
}
419+
420+
return std::make_pair(CScript(), 0);
421+
}

src/policy/policy.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <cstdint>
1616
#include <string>
1717
#include <unordered_set>
18+
#include <utility>
1819

1920
class CCoinsViewCache;
2021
class CFeeRate;
@@ -185,4 +186,6 @@ static inline int64_t GetVirtualTransactionInputSize(const CTxIn& tx)
185186
return GetVirtualTransactionInputSize(tx, 0, 0);
186187
}
187188

189+
std::pair<CScript, unsigned int> GetScriptForTransactionInput(CScript prevScript, const CTxIn&);
190+
188191
#endif // BITCOIN_POLICY_POLICY_H

0 commit comments

Comments
 (0)