Skip to content

Emit beholder message for Atlas userOp#447

Merged
dimriou merged 7 commits intodevelopfrom
oev-1266_userOp_data_submission
Apr 29, 2026
Merged

Emit beholder message for Atlas userOp#447
dimriou merged 7 commits intodevelopfrom
oev-1266_userOp_data_submission

Conversation

@dimriou
Copy link
Copy Markdown
Contributor

@dimriou dimriou commented Apr 24, 2026

Depends on (need to bump dep ref after merge):

This PR enables sending userOp data.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 24, 2026

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

⚠️ Breaking Changes (1)

pkg/txm/clientwrappers/dualbroadcast.Response (1)
  • Error — Type changed:
  struct{ErrorMessage string "json:\"message,
  - omitempty\""}
  + omitempty\""; Data struct{UserOpHash github.com/ethereum/go-ethereum/common.Hash "json:\"userOpHash,
  + omitempty\""}}
)

📄 View full apidiff report

@dimriou dimriou force-pushed the oev-1266_userOp_data_submission branch from 2819694 to 3a30336 Compare April 24, 2026 15:55
@dimriou dimriou force-pushed the oev-1266_userOp_data_submission branch from 8de2701 to 2a3a953 Compare April 27, 2026 08:30
req.Header.Add("Content-Type", "application/json")

resp, err := http.DefaultClient.Do(req)
responseReceivedAt := time.Now().UnixMicro()
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.

Do we need microseconds?

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.

It's used here, I was just being consistent.

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.

Good point, then I guess there's a reason for it, though I can't remember why we didn't just use UnixMilli()

a.metrics.RecordBidsReceived(ctx, len(response.Result.SOS))
userOpHash := common.Hash{}
if response.Result.DO != nil {
userOpHash = response.Result.DO.UserOpHash //
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.

Empty comment?

UseProtoNames: true,
EmitUnpopulated: true,
}.Format(msg)
m.lggr.Infow("[Beholder.emit]", "message", mStr, "attributes", attrKVs)
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.

Maybe this should be debug, it will pollute the logs a lot

m.lggr.Debugw("Successfully emitted Atlas error event to Beholder", "message", mStr, "attributes", attrKVs)
}

func (m *MetaMetrics) emitAtlasUserOp(ctx context.Context, userOpHash common.Hash, tx *types.Transaction, requestSentAt, responseReceivedAt int64) {
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.

We're not returning all error conditions, maybe we should return them and in the caller log + ignore?

Copy link
Copy Markdown
Contributor Author

@dimriou dimriou Apr 27, 2026

Choose a reason for hiding this comment

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

Which error conditions are you thinking of? This is in-line with emitAtlasError, unless you're talking about the caller.

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.

Right yeah, it's indeed in line with emitAtlasError. Ok then let's keep it as-is

@dimriou dimriou marked this pull request as ready for review April 29, 2026 09:02
@dimriou dimriou requested a review from a team as a code owner April 29, 2026 09:02
Copilot AI review requested due to automatic review settings April 29, 2026 09:02
@dimriou dimriou requested a review from a team as a code owner April 29, 2026 09:02
@dimriou dimriou enabled auto-merge (squash) April 29, 2026 09:02
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 adds Beholder event emission for Atlas user operation (userOp) data from the dualbroadcast MetaClient flow, enabling downstream observability of userOp hash + timing + lifecycle metadata.

Changes:

  • Add MetaMetrics.emitAtlasUserOp to emit pb.FastLaneAtlasUserOp to Beholder (including lifecycle ID and request/response timestamps).
  • Emit the userOp event from MetaClient.SendRequest for both success and JSON-RPC error responses (when a userOpHash is present).
  • Add a unit test validating the emitted protobuf payload for the userOp event.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
pkg/txm/clientwrappers/dualbroadcast/meta_metrics.go Implements Beholder emission for FastLaneAtlasUserOp and adjusts Beholder emit logging for errors.
pkg/txm/clientwrappers/dualbroadcast/meta_client.go Captures request/response timestamps and triggers userOp emission on both error and success responses.
pkg/txm/clientwrappers/dualbroadcast/meta_metrics_test.go Adds a unit test for emitAtlasUserOp validating emitted protobuf fields.

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


meta, err := tx.GetMeta()
if err != nil {
m.lggr.Errorw("Failed to get meta for tx. UserOpHash to emit was: "+userOpHash.Hex(), "txId", tx.ID, "err", err)
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

In the GetMeta() error path, the log message is built via string concatenation to include the userOpHash. For consistency with other structured logs (and to keep the message stable for log parsing), pass userOpHash as its own key/value field (e.g., "userOpHash", userOpHash.Hex()) instead of embedding it into the message string.

Suggested change
m.lggr.Errorw("Failed to get meta for tx. UserOpHash to emit was: "+userOpHash.Hex(), "txId", tx.ID, "err", err)
m.lggr.Errorw("Failed to get meta for tx", "txId", tx.ID, "userOpHash", userOpHash.Hex(), "err", err)

Copilot uses AI. Check for mistakes.
})
}

func TestMetaClient_emitAtlasUserOp(t *testing.T) {
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

This test function name says "MetaClient" but it’s validating MetaMetrics.emitAtlasUserOp. Renaming it (e.g., to TestMetaMetrics_emitAtlasUserOp) would make failures easier to interpret and keep test naming accurate.

Suggested change
func TestMetaClient_emitAtlasUserOp(t *testing.T) {
func TestMetaMetrics_emitAtlasUserOp(t *testing.T) {

Copilot uses AI. Check for mistakes.
Comment on lines +173 to +183
func (m *MetaMetrics) emitAtlasUserOp(ctx context.Context, userOpHash common.Hash, tx *types.Transaction, requestSentAt, responseReceivedAt int64) {
var nonce string
if tx.Nonce != nil {
nonce = strconv.FormatUint(*tx.Nonce, 10)
}

meta, err := tx.GetMeta()
if err != nil {
m.lggr.Errorw("Failed to get meta for tx. UserOpHash to emit was: "+userOpHash.Hex(), "txId", tx.ID, "err", err)
return
}
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

emitAtlasUserOp introduces multiple branches (nil nonce, nil/invalid meta, and emitter.Emit error handling) but the new tests only cover the fully-populated happy path. Adding coverage for the other branches (similar to the existing emitAtlasError tests) would help prevent regressions in these error-handling paths.

Copilot uses AI. Check for mistakes.
cll-gg
cll-gg previously approved these changes Apr 29, 2026
@dimriou dimriou merged commit a6c5f73 into develop Apr 29, 2026
34 checks passed
@dimriou dimriou deleted the oev-1266_userOp_data_submission branch April 29, 2026 10:55
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.

4 participants