Skip to content

Commit b716189

Browse files
committed
Ability to ignore IsStandardTx rejection reasons
1 parent 9ebc373 commit b716189

File tree

3 files changed

+39
-22
lines changed

3 files changed

+39
-22
lines changed

src/policy/policy.cpp

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
6767
return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn));
6868
}
6969

70+
/**
71+
* Note this must assign whichType even if returning false, in case
72+
* IsStandardTx ignores the "scriptpubkey" rejection.
73+
*/
7074
bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_datacarrier_bytes, TxoutType& whichType)
7175
{
7276
std::vector<std::vector<unsigned char> > vSolutions;
@@ -91,11 +95,27 @@ bool IsStandard(const CScript& scriptPubKey, const std::optional<unsigned>& max_
9195
return true;
9296
}
9397

94-
bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason)
98+
static inline bool MaybeReject_(std::string& out_reason, const std::string& reason, const std::string& reason_prefix, const ignore_rejects_type& ignore_rejects) {
99+
if (ignore_rejects.count(reason_prefix + reason)) {
100+
return false;
101+
}
102+
103+
out_reason = reason_prefix + reason;
104+
return true;
105+
}
106+
107+
#define MaybeReject(reason) do { \
108+
if (MaybeReject_(out_reason, reason, reason_prefix, ignore_rejects)) { \
109+
return false; \
110+
} \
111+
} while(0)
112+
113+
bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& out_reason, const ignore_rejects_type& ignore_rejects)
95114
{
115+
const std::string reason_prefix;
116+
96117
if (tx.version > TX_MAX_STANDARD_VERSION || tx.version < 1) {
97-
reason = "version";
98-
return false;
118+
MaybeReject("version");
99119
}
100120

101121
// Extremely large transactions with lots of inputs can cost the network
@@ -104,8 +124,7 @@ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_dat
104124
// to MAX_STANDARD_TX_WEIGHT mitigates CPU exhaustion attacks.
105125
unsigned int sz = GetTransactionWeight(tx);
106126
if (sz > MAX_STANDARD_TX_WEIGHT) {
107-
reason = "tx-size";
108-
return false;
127+
MaybeReject("tx-size");
109128
}
110129

111130
for (const CTxIn& txin : tx.vin)
@@ -119,41 +138,39 @@ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_dat
119138
// 20-of-20 CHECKMULTISIG scriptPubKey, though such a scriptPubKey
120139
// is not considered standard.
121140
if (txin.scriptSig.size() > MAX_STANDARD_SCRIPTSIG_SIZE) {
122-
reason = "scriptsig-size";
123-
return false;
141+
MaybeReject("scriptsig-size");
124142
}
125143
if (!txin.scriptSig.IsPushOnly()) {
126-
reason = "scriptsig-not-pushonly";
127-
return false;
144+
MaybeReject("scriptsig-not-pushonly");
128145
}
129146
}
130147

131148
unsigned int nDataOut = 0;
132149
TxoutType whichType;
133150
for (const CTxOut& txout : tx.vout) {
134151
if (!::IsStandard(txout.scriptPubKey, max_datacarrier_bytes, whichType)) {
135-
reason = "scriptpubkey";
136152
if (whichType == TxoutType::WITNESS_UNKNOWN) {
137-
reason += "-unknown-witnessversion";
153+
MaybeReject("scriptpubkey-unknown-witnessversion");
154+
} else {
155+
MaybeReject("scriptpubkey");
138156
}
139-
return false;
140157
}
141158

142-
if (whichType == TxoutType::NULL_DATA)
159+
if (whichType == TxoutType::NULL_DATA) {
143160
nDataOut++;
161+
continue;
162+
}
144163
else if ((whichType == TxoutType::MULTISIG) && (!permit_bare_multisig)) {
145-
reason = "bare-multisig";
146-
return false;
147-
} else if (IsDust(txout, dust_relay_fee)) {
148-
reason = "dust";
149-
return false;
164+
MaybeReject("bare-multisig");
165+
}
166+
if (IsDust(txout, dust_relay_fee)) {
167+
MaybeReject("dust");
150168
}
151169
}
152170

153171
// only one OP_RETURN txout is permitted
154172
if (nDataOut > 1) {
155-
reason = "multi-op-return";
156-
return false;
173+
MaybeReject("multi-op-return");
157174
}
158175

159176
return true;

src/policy/policy.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ static constexpr decltype(CTransaction::version) TX_MAX_STANDARD_VERSION{3};
141141
* Check for standard transaction types
142142
* @return True if all outputs (scriptPubKeys) use only standard transaction forms
143143
*/
144-
bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason);
144+
bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& out_reason, const ignore_rejects_type& ignore_rejects=empty_ignore_rejects);
145145
/**
146146
* Check for standard transaction types
147147
* @param[in] mapInputs Map of previous transactions that have outputs we're spending

src/validation.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
810810

811811
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
812812
std::string reason;
813-
if (m_pool.m_opts.require_standard && !IsStandardTx(tx, m_pool.m_opts.max_datacarrier_bytes, m_pool.m_opts.permit_bare_multisig, m_pool.m_opts.dust_relay_feerate, reason)) {
813+
if (m_pool.m_opts.require_standard && !IsStandardTx(tx, m_pool.m_opts.max_datacarrier_bytes, m_pool.m_opts.permit_bare_multisig, m_pool.m_opts.dust_relay_feerate, reason, ignore_rejects)) {
814814
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason);
815815
}
816816

0 commit comments

Comments
 (0)