#include <policy/policy.h>
#include <coins.h>
#include <consensus/amount.h>
#include <consensus/consensus.h>
#include <consensus/validation.h>
#include <policy/feerate.h>
#include <primitives/transaction.h>
#include <script/interpreter.h>
#include <script/script.h>
#include <script/solver.h>
#include <serialize.h>
#include <span.h>
#include <tinyformat.h>
#include <algorithm>
#include <cstddef>
#include <vector>
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
{
if (txout.scriptPubKey.IsUnspendable())
return 0;
uint64_t nSize{GetSerializeSize(txout)};
int witnessversion = 0;
std::vector<unsigned char> witnessprogram;
if (txout.scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
nSize += (32 + 4 + 1 + (107 / WITNESS_SCALE_FACTOR) + 4);
} else {
nSize += (32 + 4 + 1 + 107 + 4); }
return dustRelayFeeIn.GetFee(nSize);
}
bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
{
return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn));
}
std::vector<uint32_t> GetDust(const CTransaction& tx, CFeeRate dust_relay_rate)
{
std::vector<uint32_t> dust_outputs;
for (uint32_t i{0}; i < tx.vout.size(); ++i) {
if (IsDust(tx.vout[i], dust_relay_rate)) dust_outputs.push_back(i);
}
return dust_outputs;
}
bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType)
{
std::vector<std::vector<unsigned char> > vSolutions;
whichType = Solver(scriptPubKey, vSolutions);
if (whichType == TxoutType::NONSTANDARD) {
return false;
} else if (whichType == TxoutType::MULTISIG) {
unsigned char m = vSolutions.front()[0];
unsigned char n = vSolutions.back()[0];
if (n < 1 || n > 3)
return false;
if (m < 1 || m > n)
return false;
}
return true;
}
bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason)
{
if (tx.version > TX_MAX_STANDARD_VERSION || tx.version < TX_MIN_STANDARD_VERSION) {
reason = "version";
return false;
}
unsigned int sz = GetTransactionWeight(tx);
if (sz > MAX_STANDARD_TX_WEIGHT) {
reason = "tx-size";
return false;
}
for (const CTxIn& txin : tx.vin)
{
if (txin.scriptSig.size() > MAX_STANDARD_SCRIPTSIG_SIZE) {
reason = "scriptsig-size";
return false;
}
if (!txin.scriptSig.IsPushOnly()) {
reason = "scriptsig-not-pushonly";
return false;
}
}
unsigned int datacarrier_bytes_left = max_datacarrier_bytes.value_or(0);
TxoutType whichType;
for (const CTxOut& txout : tx.vout) {
if (!::IsStandard(txout.scriptPubKey, whichType)) {
reason = "scriptpubkey";
return false;
}
if (whichType == TxoutType::NULL_DATA) {
unsigned int size = txout.scriptPubKey.size();
if (size > datacarrier_bytes_left) {
reason = "datacarrier";
return false;
}
datacarrier_bytes_left -= size;
} else if ((whichType == TxoutType::MULTISIG) && (!permit_bare_multisig)) {
reason = "bare-multisig";
return false;
}
}
if (GetDust(tx, dust_relay_fee).size() > MAX_DUST_OUTPUTS_PER_TX) {
reason = "dust";
return false;
}
return true;
}
static bool CheckSigopsBIP54(const CTransaction& tx, const CCoinsViewCache& inputs)
{
Assert(!tx.IsCoinBase());
unsigned int sigops{0};
for (const auto& txin: tx.vin) {
const auto& prev_txo{inputs.AccessCoin(txin.prevout).out};
sigops += txin.scriptSig.GetSigOpCount(true);
sigops += prev_txo.scriptPubKey.GetSigOpCount(txin.scriptSig);
if (sigops > MAX_TX_LEGACY_SIGOPS) {
return false;
}
}
return true;
}
TxValidationState ValidateInputsStandardness(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
TxValidationState state;
if (tx.IsCoinBase()) {
return state; }
if (!CheckSigopsBIP54(tx, mapInputs)) {
state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs", "non-witness sigops exceed bip54 limit");
return state;
}
for (unsigned int i = 0; i < tx.vin.size(); i++) {
const CTxOut& prev = mapInputs.AccessCoin(tx.vin[i].prevout).out;
std::vector<std::vector<unsigned char> > vSolutions;
TxoutType whichType = Solver(prev.scriptPubKey, vSolutions);
if (whichType == TxoutType::NONSTANDARD) {
state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs", strprintf("input %u script unknown", i));
return state;
} else if (whichType == TxoutType::WITNESS_UNKNOWN) {
state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs", strprintf("input %u witness program is undefined", i));
return state;
} else if (whichType == TxoutType::SCRIPTHASH) {
std::vector<std::vector<unsigned char> > stack;
ScriptError serror;
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE, &serror)) {
state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs", strprintf("p2sh scriptsig malformed (input %u: %s)", i, ScriptErrorString(serror)));
return state;
}
if (stack.empty()) {
state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs", strprintf("input %u P2SH redeemscript missing", i));
return state;
}
CScript subscript(stack.back().begin(), stack.back().end());
unsigned int sigop_count = subscript.GetSigOpCount(true);
if (sigop_count > MAX_P2SH_SIGOPS) {
state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs", strprintf("p2sh redeemscript sigops exceed limit (input %u: %u > %u)", i, sigop_count, MAX_P2SH_SIGOPS));
return state;
}
}
}
return state;
}
bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
{
if (tx.IsCoinBase())
return true;
for (unsigned int i = 0; i < tx.vin.size(); i++)
{
if (tx.vin[i].scriptWitness.IsNull())
continue;
const CTxOut &prev = mapInputs.AccessCoin(tx.vin[i].prevout).out;
CScript prevScript = prev.scriptPubKey;
if (prevScript.IsPayToAnchor()) {
return false;
}
bool p2sh = false;
if (prevScript.IsPayToScriptHash()) {
std::vector <std::vector<unsigned char> > stack;
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE))
return false;
if (stack.empty())
return false;
prevScript = CScript(stack.back().begin(), stack.back().end());
p2sh = true;
}
int witnessversion = 0;
std::vector<unsigned char> witnessprogram;
if (!prevScript.IsWitnessProgram(witnessversion, witnessprogram))
return false;
if (witnessversion == 0 && witnessprogram.size() == WITNESS_V0_SCRIPTHASH_SIZE) {
if (tx.vin[i].scriptWitness.stack.back().size() > MAX_STANDARD_P2WSH_SCRIPT_SIZE)
return false;
size_t sizeWitnessStack = tx.vin[i].scriptWitness.stack.size() - 1;
if (sizeWitnessStack > MAX_STANDARD_P2WSH_STACK_ITEMS)
return false;
for (unsigned int j = 0; j < sizeWitnessStack; j++) {
if (tx.vin[i].scriptWitness.stack[j].size() > MAX_STANDARD_P2WSH_STACK_ITEM_SIZE)
return false;
}
}
if (witnessversion == 1 && witnessprogram.size() == WITNESS_V1_TAPROOT_SIZE && !p2sh) {
std::span stack{tx.vin[i].scriptWitness.stack};
if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) {
return false;
}
if (stack.size() >= 2) {
const auto& control_block = SpanPopBack(stack);
SpanPopBack(stack); if (control_block.empty()) return false; if ((control_block[0] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSCRIPT) {
for (const auto& item : stack) {
if (item.size() > MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE) return false;
}
}
} else if (stack.size() == 1) {
} else {
return false;
}
}
}
return true;
}
bool SpendsNonAnchorWitnessProg(const CTransaction& tx, const CCoinsViewCache& prevouts)
{
if (tx.IsCoinBase()) {
return false;
}
int version;
std::vector<uint8_t> program;
for (const auto& txin: tx.vin) {
const auto& prev_spk{prevouts.AccessCoin(txin.prevout).out.scriptPubKey};
if (prev_spk.IsWitnessProgram(version, program) && !prev_spk.IsPayToAnchor(version, program)) {
return true;
}
if (prev_spk.IsPayToScriptHash()) {
std::vector <std::vector<uint8_t>> stack;
if (!EvalScript(stack, txin.scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker{}, SigVersion::BASE)
|| stack.empty()) {
continue;
}
const CScript redeem_script{stack.back().begin(), stack.back().end()};
if (redeem_script.IsWitnessProgram(version, program)) {
return true;
}
}
}
return false;
}
int64_t GetSigOpsAdjustedWeight(int64_t weight, int64_t sigop_cost, unsigned int bytes_per_sigop)
{
return std::max(weight, sigop_cost * bytes_per_sigop);
}
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost, unsigned int bytes_per_sigop)
{
return (GetSigOpsAdjustedWeight(nWeight, nSigOpCost, bytes_per_sigop) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR;
}
int64_t GetVirtualTransactionSize(const CTransaction& tx, int64_t nSigOpCost, unsigned int bytes_per_sigop)
{
return GetVirtualTransactionSize(GetTransactionWeight(tx), nSigOpCost, bytes_per_sigop);
}
int64_t GetVirtualTransactionInputSize(const CTxIn& txin, int64_t nSigOpCost, unsigned int bytes_per_sigop)
{
return GetVirtualTransactionSize(GetTransactionInputWeight(txin), nSigOpCost, bytes_per_sigop);
}