Skip to content

Commit

Permalink
Support sub-second reports
Browse files Browse the repository at this point in the history
  • Loading branch information
samsondav committed Feb 27, 2025
1 parent d86af83 commit c9e4f02
Show file tree
Hide file tree
Showing 26 changed files with 684 additions and 201 deletions.
11 changes: 11 additions & 0 deletions .changeset/empty-terms-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"chainlink": major
---

Upgrade LLO protocol to support sub-seconds reports. #breaking_change

CAUTION: This release needs a careful rollout. It _must_ be tested on a staging DON first by setting half of the nodes to this version, while leaving half at the previous version, to verify inter-version interoperability before node-by-node rollout in production.

NOTE: Protocol version 0 does NOT support gapless handover on sub-second reports. You must upgrade to version 1 for that.

Rollout plan is here: https://smartcontract-it.atlassian.net/browse/MERC-6852
2 changes: 1 addition & 1 deletion core/scripts/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ require (
github.com/shopspring/decimal v1.4.0
github.com/smartcontractkit/chainlink-automation v0.8.1
github.com/smartcontractkit/chainlink-common v0.4.2-0.20250225100621-f0e1dd7b7942
github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250224190032-809e4b8cf29e
github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250227153942-a0fa942e8545
github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250227012921-08252fd61672
github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.22
github.com/smartcontractkit/libocr v0.0.0-20250220133800-f3b940c4f298
Expand Down
4 changes: 2 additions & 2 deletions core/scripts/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1095,8 +1095,8 @@ github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250214202341-4
github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250214202341-4190f2db1c01/go.mod h1:Bmwq4lNb5tE47sydN0TKetcLEGbgl+VxHEWp4S0LI60=
github.com/smartcontractkit/chainlink-common v0.4.2-0.20250225100621-f0e1dd7b7942 h1:z73HRzp3NmTS+8UQLisIUdqfW/TrFMe8hEgqHxFnpHc=
github.com/smartcontractkit/chainlink-common v0.4.2-0.20250225100621-f0e1dd7b7942/go.mod h1:YQuXIqQpmpAqstWV0LHaDTJ5nsSWuip5ivEM+Fisb+4=
github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250224190032-809e4b8cf29e h1:QBG+Wn5rHAi4gjnBAq6x6CZj/GjWAahFjj81VhQEu6U=
github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250224190032-809e4b8cf29e/go.mod h1:2yUpKW1/jFxpozO/Zkh3fKDzI0jthXoEcU2xuDq+vlo=
github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250227153942-a0fa942e8545 h1:Bjc0cZ9nyT6UFBF/L3dbgI1rcqS2Ucin5Orr3f1aimU=
github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250227153942-a0fa942e8545/go.mod h1:2yUpKW1/jFxpozO/Zkh3fKDzI0jthXoEcU2xuDq+vlo=
github.com/smartcontractkit/chainlink-feeds v0.1.1 h1:JzvUOM/OgGQA1sOqTXXl52R6AnNt+Wg64sVG+XSA49c=
github.com/smartcontractkit/chainlink-feeds v0.1.1/go.mod h1:55EZ94HlKCfAsUiKUTNI7QlE/3d3IwTlsU3YNa/nBb4=
github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250207205350-420ccacab78a h1:zllQ6pOs1T0oiDNK3EHr7ABy1zHp+2oxoCuVE/hK+uI=
Expand Down
4 changes: 2 additions & 2 deletions core/services/llo/bm/dummy_transmitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ func (t *transmitter) Transmit(
"report.Report.ConfigDigest", r.ConfigDigest,
"report.Report.SeqNr", r.SeqNr,
"report.Report.ChannelID", r.ChannelID,
"report.Report.ValidAfterSeconds", r.ValidAfterSeconds,
"report.Report.ObservationTimestampSeconds", r.ObservationTimestampSeconds,
"report.Report.ValidAfterNanoseconds", r.ValidAfterNanoseconds,
"report.Report.ObservationTimestampNanoseconds", r.ObservationTimestampNanoseconds,
"report.Report.Values", r.Values,
"report.Report.Specimen", r.Specimen,
)
Expand Down
23 changes: 23 additions & 0 deletions core/services/llo/evm/report_codec_common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package evm

import (
"fmt"
"math"

"github.com/smartcontractkit/chainlink-data-streams/llo"
)

// Extracts nanosecond timestamps as uint32 number of seconds
func ExtractTimestamps(report llo.Report) (validAfterSeconds, observationTimestampSeconds uint32, err error) {
vas := report.ValidAfterNanoseconds / 1e9

Check failure on line 12 in core/services/llo/evm/report_codec_common.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests_integration)

report.ValidAfterNanoseconds undefined (type "github.com/smartcontractkit/chainlink-data-streams/llo".Report has no field or method ValidAfterNanoseconds)

Check failure on line 12 in core/services/llo/evm/report_codec_common.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_fuzz)

report.ValidAfterNanoseconds undefined (type "github.com/smartcontractkit/chainlink-data-streams/llo".Report has no field or method ValidAfterNanoseconds)

Check failure on line 12 in core/services/llo/evm/report_codec_common.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

report.ValidAfterNanoseconds undefined (type "github.com/smartcontractkit/chainlink-data-streams/llo".Report has no field or method ValidAfterNanoseconds)

Check failure on line 12 in core/services/llo/evm/report_codec_common.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

report.ValidAfterNanoseconds undefined (type "github.com/smartcontractkit/chainlink-data-streams/llo".Report has no field or method ValidAfterNanoseconds)

Check failure on line 12 in core/services/llo/evm/report_codec_common.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

report.ValidAfterNanoseconds undefined (type "github.com/smartcontractkit/chainlink-data-streams/llo".Report has no field or method ValidAfterNanoseconds)

Check failure on line 12 in core/services/llo/evm/report_codec_common.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_race_tests)

report.ValidAfterNanoseconds undefined (type "github.com/smartcontractkit/chainlink-data-streams/llo".Report has no field or method ValidAfterNanoseconds)

Check failure on line 12 in core/services/llo/evm/report_codec_common.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_race_tests)

report.ValidAfterNanoseconds undefined (type "github.com/smartcontractkit/chainlink-data-streams/llo".Report has no field or method ValidAfterNanoseconds)

Check failure on line 12 in core/services/llo/evm/report_codec_common.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_race_tests)

report.ValidAfterNanoseconds undefined (type "github.com/smartcontractkit/chainlink-data-streams/llo".Report has no field or method ValidAfterNanoseconds)
ots := report.ObservationTimestampNanoseconds / 1e9

Check failure on line 13 in core/services/llo/evm/report_codec_common.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests_integration)

report.ObservationTimestampNanoseconds undefined (type "github.com/smartcontractkit/chainlink-data-streams/llo".Report has no field or method ObservationTimestampNanoseconds)

Check failure on line 13 in core/services/llo/evm/report_codec_common.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_fuzz)

report.ObservationTimestampNanoseconds undefined (type "github.com/smartcontractkit/chainlink-data-streams/llo".Report has no field or method ObservationTimestampNanoseconds)

Check failure on line 13 in core/services/llo/evm/report_codec_common.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

report.ObservationTimestampNanoseconds undefined (type "github.com/smartcontractkit/chainlink-data-streams/llo".Report has no field or method ObservationTimestampNanoseconds)

Check failure on line 13 in core/services/llo/evm/report_codec_common.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

report.ObservationTimestampNanoseconds undefined (type "github.com/smartcontractkit/chainlink-data-streams/llo".Report has no field or method ObservationTimestampNanoseconds)

Check failure on line 13 in core/services/llo/evm/report_codec_common.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_tests)

report.ObservationTimestampNanoseconds undefined (type "github.com/smartcontractkit/chainlink-data-streams/llo".Report has no field or method ObservationTimestampNanoseconds)

Check failure on line 13 in core/services/llo/evm/report_codec_common.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_race_tests)

report.ObservationTimestampNanoseconds undefined (type "github.com/smartcontractkit/chainlink-data-streams/llo".Report has no field or method ObservationTimestampNanoseconds)

Check failure on line 13 in core/services/llo/evm/report_codec_common.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_race_tests)

report.ObservationTimestampNanoseconds undefined (type "github.com/smartcontractkit/chainlink-data-streams/llo".Report has no field or method ObservationTimestampNanoseconds)

Check failure on line 13 in core/services/llo/evm/report_codec_common.go

View workflow job for this annotation

GitHub Actions / Core Tests (go_core_race_tests)

report.ObservationTimestampNanoseconds undefined (type "github.com/smartcontractkit/chainlink-data-streams/llo".Report has no field or method ObservationTimestampNanoseconds)
if vas > math.MaxUint32 {
err = fmt.Errorf("validAfterSeconds too large: %d", vas)
return
}
if ots > math.MaxUint32 {
err = fmt.Errorf("observationTimestampSeconds too large: %d", ots)
return
}
return uint32(vas), uint32(ots), nil
}
11 changes: 8 additions & 3 deletions core/services/llo/evm/report_codec_evm_abi_encode_unpacked.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,18 @@ func (r ReportCodecEVMABIEncodeUnpacked) Encode(ctx context.Context, report llo.
return nil, fmt.Errorf("failed to decode opts; got: '%s'; %w", cd.Opts, err)
}

validAfterSeconds, observationTimestampSeconds, err := ExtractTimestamps(report)
if err != nil {
return nil, fmt.Errorf("failed to extract timestamps; %w", err)
}

rf := BaseReportFields{
FeedID: opts.FeedID,
ValidFromTimestamp: report.ValidAfterSeconds + 1,
Timestamp: report.ObservationTimestampSeconds,
ValidFromTimestamp: validAfterSeconds + 1,
Timestamp: observationTimestampSeconds,
NativeFee: CalculateFee(nativePrice, opts.BaseUSDFee),
LinkFee: CalculateFee(linkPrice, opts.BaseUSDFee),
ExpiresAt: report.ObservationTimestampSeconds + opts.ExpirationWindow,
ExpiresAt: observationTimestampSeconds + opts.ExpirationWindow,
}

header, err := r.buildHeader(ctx, rf)
Expand Down
Loading

0 comments on commit c9e4f02

Please sign in to comment.