Skip to content

Conversation

ismaelsadeeq
Copy link
Member

This PR is another attempt at #13525.

Transactions that fail PreChecks Validation due to non-standard inputs now returns invalid validation stateTxValidationResult::TX_INPUTS_NOT_STANDARD along with a debug error message.

Previously, the debug error message for non-standard inputs do not specify why the inputs were considered non-standard.
Instead, the same error string, bad-txns-nonstandard-inputs, used for all types of non-standard input scriptSigs.

This PR updates the AreInputsStandard to include the reason why inputs are non-standard in the debug message.
This improves the Precheck debug message to be more descriptive.

Furthermore, I have addressed all remaining comments from #13525 in this PR.

@DrahtBot
Copy link
Contributor

DrahtBot commented Dec 12, 2023

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Code Coverage & Benchmarks

For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/29060.

Reviews

See the guideline for information on the review process.

Type Reviewers
Concept ACK stickies-v

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #32729 (test,refactor: extract script template helpers & widen sigop count coverage by l0rinc)
  • #32317 (kernel: Separate UTXO set access from validation functions by TheCharlatan)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

LLM Linter (✨ experimental)

Possible typos and grammar issues:

  • “too many signature operations that exceeds MAX_P2SH_SIGOPS” -> “too many signature operations that exceed MAX_P2SH_SIGOPS” [plural “operations” requires “exceed”]

drahtbot_id_4_m

@ismaelsadeeq ismaelsadeeq force-pushed the 11-2023-non-standard-inputs-error-messages branch from 3fc397a to 6ffb956 Compare December 12, 2023 13:48
Copy link
Contributor

@stickies-v stickies-v left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK

@ismaelsadeeq ismaelsadeeq force-pushed the 11-2023-non-standard-inputs-error-messages branch from 6ffb956 to e032462 Compare December 14, 2023 11:43
@ismaelsadeeq
Copy link
Member Author

Thank you for review @stickies-v

I Addressed your comments and taken suggestions.
Force pushed from 6ffb956 to e032462 , Compare diff

@ismaelsadeeq ismaelsadeeq force-pushed the 11-2023-non-standard-inputs-error-messages branch from e032462 to 814571b Compare December 18, 2023 14:53
@ismaelsadeeq
Copy link
Member Author

ismaelsadeeq commented Dec 18, 2023

Thanks for reviewing @luke-jr
Force pushed from e032462 to 0a39b07

Compare diff

The changes in latest push are:

  • Rebased on master to fix CI
  • Updated the non-standardness reason to address @luke-jr comments
  • bad-txns-input-script-nonstandard --> bad-txns-input-script-unknown
  • bad-txns-input-scriptsig-failure --> bad-txns-input-p2sh-scriptsig-malformed
  • bad-txns-input-p2sh-no-redeemscript --> bad-txns-input-scriptcheck-missing
  • bad-txns-input-scriptcheck-sigops --> bad-txns-input-p2sh-redeemscript-sigops

@ismaelsadeeq ismaelsadeeq force-pushed the 11-2023-non-standard-inputs-error-messages branch from 814571b to 0a39b07 Compare December 18, 2023 15:46
@ismaelsadeeq ismaelsadeeq force-pushed the 11-2023-non-standard-inputs-error-messages branch 2 times, most recently from d9e71f0 to 5ef3f9b Compare December 24, 2023 14:41
@ismaelsadeeq ismaelsadeeq force-pushed the 11-2023-non-standard-inputs-error-messages branch from 5ef3f9b to f4c1945 Compare January 25, 2024 23:05
@ismaelsadeeq
Copy link
Member Author

Rebased on master for green CI.

@achow101 achow101 requested review from luke-jr and glozow April 9, 2024 15:37
@ismaelsadeeq ismaelsadeeq requested a review from stickies-v April 24, 2024 14:30
@ismaelsadeeq ismaelsadeeq force-pushed the 11-2023-non-standard-inputs-error-messages branch from f4c1945 to 101a308 Compare May 17, 2024 08:00
@ismaelsadeeq ismaelsadeeq force-pushed the 11-2023-non-standard-inputs-error-messages branch from 101a308 to 3ef7ac6 Compare September 14, 2024 11:51
@tdb3
Copy link
Contributor

tdb3 commented Nov 2, 2024

Does bitcoind consider this to be a breaking change? The new error message may be "more accurate", but for clients that were matching on this error to figure out why a transaction was rejected, this breaks old behavior.

I've added a release notes for this

The release note helps a lot. To err on the side of caution, it seems appropriate to include a -deprecatedrpc= option, to enable a period of deprecation for users.

@ismaelsadeeq
Copy link
Member Author

The release note helps a lot. To err on the side of caution, it seems appropriate to include a -deprecatedrpc= option, to enable a period of deprecation for users.

Thanks for your review @tdb3 will address this comment soon.

@ismaelsadeeq
Copy link
Member Author

The release note helps a lot. To err on the side of caution, it seems appropriate to include a -deprecatedrpc= option, to enable a period of deprecation for users.

I attempted this, but it's a bit non trivial with some if-else branching. I also had to add a new TransactionError enum type to handle sendrawtransaction case.

see **untested** diff
diff --git a/src/common/messages.cpp b/src/common/messages.cpp
index 5fe3e9e4d86..3142ca07b4c 100644
--- a/src/common/messages.cpp
+++ b/src/common/messages.cpp
@@ -132,6 +132,8 @@ bilingual_str TransactionErrorString(const TransactionError err)
             return Untranslated("Transaction outputs already in utxo set");
         case TransactionError::MEMPOOL_REJECTED:
             return Untranslated("Transaction rejected by mempool");
+        case TransactionError::MEMPOOL_REJECTED_NON_STANDARD_INPUT:
+            return Untranslated("Transaction rejected by mempool");
         case TransactionError::MEMPOOL_ERROR:
             return Untranslated("Mempool internal error");
         case TransactionError::MAX_FEE_EXCEEDED:
diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp
index 0f45da45dbd..c35bee4ee61 100644
--- a/src/node/transaction.cpp
+++ b/src/node/transaction.cpp
@@ -25,6 +25,9 @@ static TransactionError HandleATMPError(const TxValidationState& state, std::str
         if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
             return TransactionError::MISSING_INPUTS;
         }
+        if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD) {
+            return TransactionError::MEMPOOL_REJECTED_NON_STANDARD_INPUT;
+        }
         return TransactionError::MEMPOOL_REJECTED;
     } else {
         return TransactionError::MEMPOOL_ERROR;
diff --git a/src/node/types.h b/src/node/types.h
index 1302f1b127f..5cdb696204f 100644
--- a/src/node/types.h
+++ b/src/node/types.h
@@ -21,6 +21,7 @@ enum class TransactionError {
     MISSING_INPUTS,
     ALREADY_IN_UTXO_SET,
     MEMPOOL_REJECTED,
+    MEMPOOL_REJECTED_NON_STANDARD_INPUT,
     MEMPOOL_ERROR,
     MAX_FEE_EXCEEDED,
     MAX_BURN_EXCEEDED,
diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp
index d61898260bf..a9f434fa605 100644
--- a/src/rpc/mempool.cpp
+++ b/src/rpc/mempool.cpp
@@ -95,6 +95,9 @@ static RPCHelpMan sendrawtransaction()
             NodeContext& node = EnsureAnyNodeContext(request.context);
             const TransactionError err = BroadcastTransaction(node, tx, err_string, max_raw_tx_fee, /*relay=*/true, /*wait_callback=*/true);
             if (TransactionError::OK != err) {
+                if (IsDeprecatedRPCEnabled("nonstandard-inputs-err") && err == TransactionError::MEMPOOL_REJECTED_NON_STANDARD_INPUT) {
+                    throw JSONRPCTransactionError(err, "bad-txns-nonstandard-inputs");
+                }
                 throw JSONRPCTransactionError(err, err_string);
             }
 
@@ -241,7 +244,11 @@ static RPCHelpMan testmempoolaccept()
                     if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
                         result_inner.pushKV("reject-reason", "missing-inputs");
                     } else {
-                        result_inner.pushKV("reject-reason", state.GetRejectReason());
+                        if (IsDeprecatedRPCEnabled("nonstandard-inputs-err") && state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDA
RD) {
+                            result_inner.pushKV("reject-reason", "bad-txns-nonstandard-inputs");
+                        } else {
+                            result_inner.pushKV("reject-reason", state.GetRejectReason());
+                        }
                     }
                 }
                 rpc_result.push_back(std::move(result_inner));
@@ -961,7 +968,6 @@ static RPCHelpMan submitpackage()
             }
 
             UniValue rpc_result{UniValue::VOBJ};
-            rpc_result.pushKV("package_msg", package_msg);
             UniValue tx_result_map{UniValue::VOBJ};
             std::set<uint256> replaced_txids;
             for (const auto& tx : txns) {
@@ -979,7 +985,11 @@ static RPCHelpMan submitpackage()
                     result_inner.pushKV("other-wtxid", it->second.m_other_wtxid.value().GetHex());
                     break;
                 case MempoolAcceptResult::ResultType::INVALID:
-                    result_inner.pushKV("error", it->second.m_state.ToString());
+                    if (IsDeprecatedRPCEnabled("nonstandard-inputs-err") && it->second.m_state.GetResult() == TxValidationResult::TX_INPUTS_N
OT_STANDARD){
+                        result_inner.pushKV("error", "bad-txns-nonstandard-inputs");
+                    } else {
+                        result_inner.pushKV("error", it->second.m_state.ToString());
+                    }
                     break;
                 case MempoolAcceptResult::ResultType::VALID:
                 case MempoolAcceptResult::ResultType::MEMPOOL_ENTRY:
diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp
index 678bac7a185..3653421dcae 100644
--- a/src/rpc/util.cpp
+++ b/src/rpc/util.cpp
@@ -400,6 +400,8 @@ RPCErrorCode RPCErrorFromTransactionError(TransactionError terr)
     switch (terr) {
         case TransactionError::MEMPOOL_REJECTED:
             return RPC_TRANSACTION_REJECTED;
+        case TransactionError::MEMPOOL_REJECTED_NON_STANDARD_INPUT:
+            return RPC_TRANSACTION_REJECTED;
         case TransactionError::ALREADY_IN_UTXO_SET:
             return RPC_VERIFY_ALREADY_IN_UTXO_SET;
         default: break;
diff --git a/src/test/fuzz/kitchen_sink.cpp b/src/test/fuzz/kitchen_sink.cpp
index 62b49106cdd..4df4a2c4372 100644
--- a/src/test/fuzz/kitchen_sink.cpp
+++ b/src/test/fuzz/kitchen_sink.cpp
@@ -25,6 +25,7 @@ constexpr TransactionError ALL_TRANSACTION_ERROR[] = {
     TransactionError::MISSING_INPUTS,
     TransactionError::ALREADY_IN_UTXO_SET,
     TransactionError::MEMPOOL_REJECTED,
+    TransactionError::MEMPOOL_REJECTED_NON_STANDARD_INPUT,
     TransactionError::MEMPOOL_ERROR,
     TransactionError::MAX_FEE_EXCEEDED,
 };

However, do you think it would be better to make the prefix of the message bad-txns-nonstandard-inputs and append the additional information after it?
This approach ensures that clients relying solely on pattern matching remain unaffected, as the error code remains unchanged.

The only clients that affected after the above suggestion are those performing an exact match.

Let me know what you think about the two approaches.

fanquake added a commit that referenced this pull request Mar 21, 2025
c6eca6f doc: add guidance for RPC to developer notes (tdb3)

Pull request description:

  Adds guidance statements to the RPC interface section of the developer notes with examples of when to implement `-deprecatedrpc=`.

  Wanted to increase awareness of preferred RPC implementation approaches for newer contributors.

  This implements some of what's discussed in #29912 (comment)

  Opinions may differ, so please don't be shy.  We want to make RPC as solid/safe as possible.

  Examples of discussions where guidelines/context might have added value:
  #30212 (comment)
  #29845 (comment)
  #30381 (review)
  #29954 (comment)
  #30410 (review)
  #30713
  #30381
  #29060 (review)

ACKs for top commit:
  l0rinc:
    ACK c6eca6f
  fjahr:
    ACK c6eca6f
  maflcko:
    lgtm ACK c6eca6f
  jonatack:
    ACK c6eca6f

Tree-SHA512: 01a98a8dc0eb91762b225d3278cdb4a5e380ceb7486fd096b4ad9122bed859cea8584d8996d3dce51272fdb792f4a793a1bd1c5445efeb87f0a30f9b6e59a790
@ismaelsadeeq ismaelsadeeq force-pushed the 11-2023-non-standard-inputs-error-messages branch from 02dd534 to b487edc Compare July 3, 2025 14:26
@DrahtBot
Copy link
Contributor

DrahtBot commented Jul 3, 2025

🚧 At least one of the CI tasks failed.
Task lint: https://github.com/bitcoin/bitcoin/runs/45300633777
LLM reason (✨ experimental): The CI failure is caused by a lint error related to missing a trailing newline.

Hints

Try to run the tests locally, according to the documentation. However, a CI failure may still
happen due to a number of reasons, for example:

  • Possibly due to a silent merge conflict (the changes in this pull request being
    incompatible with the current code in the target branch). If so, make sure to rebase on the latest
    commit of the target branch.

  • A sanitizer issue, which can only be found by compiling with the sanitizer and running the
    affected test.

  • An intermittent issue.

Leave a comment here, if you need help tracking down a confusing failure.

@ismaelsadeeq ismaelsadeeq force-pushed the 11-2023-non-standard-inputs-error-messages branch 2 times, most recently from 3cde7f1 to 4d5ede0 Compare July 7, 2025 16:37
@ismaelsadeeq
Copy link
Member Author

Rebased and addressed comment from @DrahtBot see diff

@DrahtBot
Copy link
Contributor

🚧 At least one of the CI tasks failed.
Task tidy: https://github.com/bitcoin/bitcoin/runs/45492221044
LLM reason (✨ experimental): The CI failure is caused by a compilation error in src/policy/policy.cpp where returning false from a function with return type TxValidationState causes a type mismatch.

Hints

Try to run the tests locally, according to the documentation. However, a CI failure may still
happen due to a number of reasons, for example:

  • Possibly due to a silent merge conflict (the changes in this pull request being
    incompatible with the current code in the target branch). If so, make sure to rebase on the latest
    commit of the target branch.

  • A sanitizer issue, which can only be found by compiling with the sanitizer and running the
    affected test.

  • An intermittent issue.

Leave a comment here, if you need help tracking down a confusing failure.

ismaelsadeeq and others added 2 commits July 21, 2025 11:55
This commit renames AreInputsStandard to HasNonStandardInput.

HasNonStandardInput now returns valid TxValidationState if all inputs
(scriptSigs) use only standard transaction forms else returns invalid
TxValidationState which states why an input is not standard.
Test the various input scriptSig non standardness, and ensure HasNonStandardInput
Returns the resin why the input is nonstandard.

Co-authored-by: Ben Woosley <ben.woosley@gmail.com>
@ismaelsadeeq ismaelsadeeq force-pushed the 11-2023-non-standard-inputs-error-messages branch from 4d5ede0 to cf63e46 Compare July 21, 2025 10:57
@ismaelsadeeq ismaelsadeeq force-pushed the 11-2023-non-standard-inputs-error-messages branch from cf63e46 to 85c6c97 Compare July 21, 2025 11:01
@ismaelsadeeq
Copy link
Member Author

Rebased after the merge of #32521 to pick up recent changes to AreInputsStandard.

A new verbose message will be returned when the BIP54 legacy sigops limit is violated:

  • bad-txns-non-witness-sigops-exceeds-bip54-limit: This occurs when the total number of non-witness sigops across the entire transaction exceeds MAX_TX_LEGACY_SIGOPS. Additionally, a debug message is also returned with the actual number of sigops and the limit, for example: sigops 2501 > limit 2500.

3cde7f185255b1bc07a90e95708665e0b6d5a46d..85c6c97b609bcbcd2b2f13638d858d5a31a903

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants