Skip to content

Upgrade error handler#408

Merged
dimriou merged 2 commits intodevelopfrom
oev-1176_upgrade_handler
Apr 15, 2026
Merged

Upgrade error handler#408
dimriou merged 2 commits intodevelopfrom
oev-1176_upgrade_handler

Conversation

@dimriou
Copy link
Copy Markdown
Contributor

@dimriou dimriou commented Apr 2, 2026

This PR upgrades error handler for TXMv2. We no longer throw an error if the handler decides there was no transmission, which results in a better observability. Additionally, if the error handler fails to parse the error, txm will check if the pending nonce increased instead of returning an error, which follows the standard flow.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 2, 2026

⚠️ API Diff Results - github.com/smartcontractkit/chainlink-evm

⚠️ Breaking Changes (3)

pkg/txm.(*txmMetrics) (1)
  • SetRPCNonce — 🗑️ Removed
pkg/txm.ErrorHandler (1)
  • HandleError — Type changed:
func(
  context.Context, 
  + github.com/smartcontractkit/chainlink-common/pkg/logger.Logger, 
  *github.com/smartcontractkit/chainlink-evm/pkg/txm/types.Transaction, 
  error, 
  TxStore, 
  func(github.com/ethereum/go-ethereum/common.Address, 
  - uint64), 
  - bool
  + uint64)
)
- error
+ (bool, error)
pkg/txm/clientwrappers/dualbroadcast.(*errorHandler) (1)
  • HandleError — Type changed:
func(
  context.Context, 
  + github.com/smartcontractkit/chainlink-common/pkg/logger.Logger, 
  *github.com/smartcontractkit/chainlink-evm/pkg/txm/types.Transaction, 
  error, 
  github.com/smartcontractkit/chainlink-evm/pkg/txm.TxStore, 
  func(github.com/ethereum/go-ethereum/common.Address, 
  - uint64), 
  - bool
  + uint64)
)
- error
+ (bool, error)

📄 View full apidiff report

@dimriou dimriou force-pushed the oev-1176_upgrade_handler branch from cab58c2 to d34d05d Compare April 2, 2026 13:01
txErr error,
txStore txm.TxStore,
setNonce func(common.Address, uint64),
isFromBroadcastMethod bool,
Copy link
Copy Markdown
Contributor

@cll-gg cll-gg Apr 6, 2026

Choose a reason for hiding this comment

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

Let's remove the unused isFromBroadcastMethod while we're touching this func anyway

txStore txm.TxStore,
setNonce func(common.Address, uint64),
isFromBroadcastMethod bool,
) (noTransmission bool, err error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nitpick: I somewhat dislike negations in var names, since it will lead to double negations, which can lead to confusion.

Maybe flip it around and use something like transmissionHappened?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Seems reasonable to me, but the issue with this particular case is that there is guarantee a transmission happened and we can only be sure about the noTransmission. If we flip the name to transmissionHappened or transmissionMayHappened and we check for the inversed result, the reader might assume that the error handler can deterministically returned if a transaction was broadcasted. It feels like noTransmission provides better conviction as to what happened.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ah I see, so otherwise it would be transmissionMightHaveHappened, which is not great 😅
Let's leave it like this then. Might be worthwhile to add a comment to the code about that we can only be 100% sure a transmission has not happened

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice!

}
setNonce(tx.FromAddress, *tx.Nonce)
return fmt.Errorf("transaction with txID: %d marked as fatal", tx.ID)
lggr.Infof("transaction with txID: %d marked as fatal", tx.ID)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we log the transactionLifecycleID here?

Comment thread pkg/txm/txm.go
if hErr != nil {
return hErr
}
if noTransmission {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would it be helpful to add a debug log here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

For now the only ErrorHandler we have implemented is the MetaErrorHandler which already logs a message if noTransmission is true, so I think we already get the information from that.

@dimriou dimriou force-pushed the oev-1176_upgrade_handler branch from 5cb2762 to 156bdfc Compare April 8, 2026 14:08
@dimriou dimriou force-pushed the oev-1176_upgrade_handler branch from 156bdfc to 37483bb Compare April 8, 2026 15:30
@dimriou dimriou marked this pull request as ready for review April 14, 2026 14:41
@dimriou dimriou requested a review from a team as a code owner April 14, 2026 14:41
Copilot AI review requested due to automatic review settings April 14, 2026 14:41
@dimriou dimriou requested a review from a team as a code owner April 14, 2026 14:41
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates TXMv2’s error-handling flow to improve observability and to fall back to the “standard” pending-nonce verification path when an error cannot be classified by the error handler.

Changes:

  • Change the txm.ErrorHandler interface to return (noTransmission bool, err error) and accept a logger, enabling non-error fatal handling and logging.
  • Update Txm.sendTransactionWithError to (a) not fail the call when the handler determines “no transmission”, and (b) check PendingNonceAt when the handler cannot classify the error.
  • Update dualbroadcast error handler + tests to log fatal marking instead of returning a fatal error, and adjust TXM tests accordingly.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
pkg/txm/txm.go Updates ErrorHandler interface and TXM send flow to use handler result + pending nonce fallback.
pkg/txm/clientwrappers/dualbroadcast/meta_error_handler.go Implements new handler contract; logs and marks tx fatal without returning an error.
pkg/txm/clientwrappers/dualbroadcast/meta_error_handler_test.go Updates unit tests for new handler behavior and adds log assertions.
pkg/txm/txm_test.go Updates flow tests to assert log output and pending-nonce fallback behavior.
Comments suppressed due to low confidence (1)

pkg/txm/txm_test.go:591

  • Same issue here: require.NotNil(t, IDK, tx.IdempotencyKey) will always pass because IDK is non-nil. This should assert on tx.IdempotencyKey (and preferably compare it to the expected value).
	require.Equal(t, 1, count)
	require.NotNil(t, IDK, tx.IdempotencyKey)
	require.Equal(t, uint16(2), tx.AttemptCount)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +85 to 88
noTransmission, err := errorHandler.HandleError(t.Context(), logger.Test(t), tx, txErr, txStoreManager, setNonce)
require.NoError(t, err)
require.False(t, noTransmission)
_, unconfirmedCount := txStore.FetchUnconfirmedTransactionAtNonceWithCount(nonce)
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

This subtest no longer returns txErr (it now expects HandleError to return err == nil and noTransmission == false), but the test name still says it does. Rename the test case to match the behavior being asserted to avoid confusion when the test fails in the future.

Copilot uses AI. Check for mistakes.
@dimriou dimriou merged commit 7d4da8a into develop Apr 15, 2026
39 checks passed
@dimriou dimriou deleted the oev-1176_upgrade_handler branch April 15, 2026 13:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants