Skip to content

[CRE-491] Move EVM relay mercury to chainlink-evm#375

Merged
pavel-raykov merged 2 commits intodevelopfrom
move-mercury2
Feb 27, 2026
Merged

[CRE-491] Move EVM relay mercury to chainlink-evm#375
pavel-raykov merged 2 commits intodevelopfrom
move-mercury2

Conversation

@pavel-raykov
Copy link
Contributor

@pavel-raykov pavel-raykov commented Feb 27, 2026

Supports smartcontractkit/chainlink#21326

Moved files from core/services/relay/evm/mercury except that:

  • Removed PeerID: utils.MustNewPeerID() initialization in config_poller_test.go (was unused)
  • Removed func (m mockCfg) Protocol() config.MercuryTransmitterProtocol from transmitter_test.go (was unused)

@github-actions
Copy link
Contributor

github-actions bot commented Feb 27, 2026

✅ API Diff Results - No breaking changes


📄 View full apidiff report

Copy link
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 migrates the EVM Mercury relay implementation into the chainlink-evm repository by introducing the Mercury transmitter, persistence/queueing, config polling, report codecs (v2–v4), feed ID utilities, and verifier logic under pkg/mercury.

Changes:

  • Added Mercury transmitter + persistence manager + DB ORM + in-memory transmit queue and associated tests.
  • Added Mercury report codecs and ABI report type definitions for v2/v3/v4, plus feed ID parsing utilities.
  • Added verifier implementation and tests for server-side report signature verification.

Reviewed changes

Copilot reviewed 34 out of 35 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pkg/mercury/verifier/verifier.go Adds server-side signature verification logic for Mercury reports.
pkg/mercury/verifier/verifier_test.go Adds tests covering authorized/unauthorized/tampered signature verification.
pkg/mercury/v4/types/types.go Defines v4 report ABI schema + decode helper.
pkg/mercury/v4/reportcodec/report_codec.go Implements v4 report codec build/decode helpers.
pkg/mercury/v4/reportcodec/report_codec_test.go Tests v4 report codec build/decode and error cases.
pkg/mercury/v3/types/types.go Defines v3 report ABI schema + decode helper.
pkg/mercury/v3/reportcodec/report_codec.go Implements v3 report codec build/decode helpers.
pkg/mercury/v3/reportcodec/report_codec_test.go Tests v3 report codec build/decode and error cases.
pkg/mercury/v2/types/types.go Defines v2 report ABI schema + decode helper.
pkg/mercury/v2/reportcodec/report_codec.go Implements v2 report codec build/decode helpers.
pkg/mercury/v2/reportcodec/report_codec_test.go Tests v2 report codec build/decode and error cases.
pkg/mercury/utils/feeds.go Adds FeedID parsing/versioning logic incl. legacy ID handling.
pkg/mercury/utils/feeds_test.go Tests feed ID version detection (including legacy/keystone cases).
pkg/mercury/types/types.go Adds shared mercury interfaces + Prometheus counters used by mercury consumers.
pkg/mercury/transmitter.go Adds Mercury transmitter implementation (enqueue, transmit loops, latest-report queries).
pkg/mercury/transmitter_test.go Adds transmitter behavior tests (enqueueing, latest timestamp/price, queue loop).
pkg/mercury/test_helpers.go Adds test helper for config digest parsing.
pkg/mercury/queue.go Adds transmit priority queue implementation + monitoring/health reporting.
pkg/mercury/queue_test.go Tests transmit queue ordering, eviction, blocking pop, and init behavior.
pkg/mercury/persistence_manager.go Adds persistence manager for queued transmissions (insert/delete/prune loops).
pkg/mercury/persistence_manager_test.go Tests persistence manager load/delete/prune behavior and job scoping.
pkg/mercury/orm.go Adds DB ORM for mercury transmit requests + latest report table updates.
pkg/mercury/orm_test.go Tests ORM insert/get/delete/prune and latest report behavior.
pkg/mercury/offchain_config_digester.go Adds mercury-specific offchain config digester implementation.
pkg/mercury/offchain_config_digester_test.go Tests config digest behavior for different chainIDs/addresses and malformed inputs.
pkg/mercury/config_poller.go Adds Mercury config poller pulling ConfigSet logs scoped by feed ID.
pkg/mercury/config_poller_test.go Integration-style test verifying config poller sees on-chain config updates.
pkg/mercury/config_digest.go Implements config digest calculation matching Solidity contract.
pkg/mercury/config_digest_test.go Property-based test ensuring Go digest matches Solidity digest.
pkg/mercury/helpers_test.go Adds broader mercury test harness helpers (contracts, logpoller, sample reports).
pkg/mercury/mocks/async_deleter.go Adds generated mock for async deletion used by transmit queue tests.
pkg/.mockery.yaml Registers asyncDeleter interface for mock generation.
go.mod Updates Go/toolchain and adds/bumps dependencies needed by the migrated Mercury code.
go.sum Updates dependency checksums accordingly.
go.md Updates dependency graph documentation to reflect new module relationships.

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

Comment on lines +47 to +51
func (o *orm) InsertTransmitRequest(ctx context.Context, serverURLs []string, req *pb.TransmitRequest, jobID int32, reportCtx ocrtypes.ReportContext) error {
feedID, err := FeedIDFromReport(req.Payload)
if err != nil {
return err
}
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

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

InsertTransmitRequest derives feedID by copying the first 32 bytes of req.Payload, but in this package req.Payload is an ABI-encoded payload (reportContext + report + sigs), so the first 32 bytes are not the report’s feed ID. This will write incorrect feed_id/feed_latest_reports keys. Derive feedID from the inner report field (ABI-unpack payload then parse the report bytes), or pass the known feedID into InsertTransmitRequest instead of parsing it from the payload.

Copilot uses AI. Check for mistakes.
Comment on lines +426 to +437
var rs [][32]byte
var ss [][32]byte
var vs [32]byte
for i, as := range signatures {
r, s, v, err := evmutil.SplitSignature(as.Signature)
if err != nil {
panic("eventTransmit(ev): error in SplitSignature")
}
rs = append(rs, r)
ss = append(ss, s)
vs[i] = v
}
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

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

Transmit writes signature recovery IDs into a fixed [32]byte (vs[i] = v) without bounding len(signatures). If more than 32 signatures are provided this will panic. Add an explicit len(signatures) > 32 guard (similar to other transmitters in the repo) and return an error.

Copilot uses AI. Check for mistakes.
Comment on lines +516 to +521
t.Run("on server-side error, does not retry", func(t *testing.T) {
transmit := make(chan *pb.TransmitRequest, 1)
c.TransmitF = func(ctx context.Context, in *pb.TransmitRequest) (*pb.TransmitResponse, error) {
transmit <- in
return &pb.TransmitResponse{Code: DuplicateReport, Error: ""}, nil
}
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

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

The subtest "on server-side error, does not retry" sets TransmitF to return DuplicateReport with an empty error string, which exercises the success/duplicate path rather than the server-side error path (res.Error != ""). Update this mock response (and assertions) so the test actually validates the intended behavior.

Copilot uses AI. Check for mistakes.
Comment on lines +236 to +239
// We want Pop to give us the latest round, so we use greater than here
// i.e. a later epoch/round is "less" than an earlier one
return pq[i].ReportCtx.Epoch > pq[j].ReportCtx.Epoch &&
pq[i].ReportCtx.Round > pq[j].ReportCtx.Round
Copy link

Copilot AI Feb 27, 2026

Choose a reason for hiding this comment

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

priorityQueue.Less uses epoch > ... && round > ..., which does not implement a strict ordering for (epoch, round) and will mis-order items whenever epoch and round move in opposite directions (e.g., (2,10) vs (3,1)). This can cause the queue to pop/evict the wrong transmission. Implement a lexicographic comparison: compare epoch first, and if equal compare round.

Suggested change
// We want Pop to give us the latest round, so we use greater than here
// i.e. a later epoch/round is "less" than an earlier one
return pq[i].ReportCtx.Epoch > pq[j].ReportCtx.Epoch &&
pq[i].ReportCtx.Round > pq[j].ReportCtx.Round
// We want Pop to give us the latest round, so we use greater than here:
// lexicographically later (epoch, round) is considered "less" than earlier.
if pq[i].ReportCtx.Epoch != pq[j].ReportCtx.Epoch {
return pq[i].ReportCtx.Epoch > pq[j].ReportCtx.Epoch
}
return pq[i].ReportCtx.Round > pq[j].ReportCtx.Round

Copilot uses AI. Check for mistakes.
@pavel-raykov pavel-raykov merged commit 0de99d1 into develop Feb 27, 2026
37 checks passed
@pavel-raykov pavel-raykov deleted the move-mercury2 branch February 27, 2026 17:52
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