Skip to content

Commit ccd12a5

Browse files
authored
fix overlap in calculated streams (#215)
1 parent 313d882 commit ccd12a5

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

llo/plugin_outcome.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,7 @@ func IsSecondsResolution(reportFormat llotypes.ReportFormat) bool {
452452
// TODO: Might be cleaner to expose a TimeResolution() uint64 field on the
453453
// ReportCodec so that the plugin doesn't have to have special knowledge of
454454
// the report format details
455-
case llotypes.ReportFormatEVMPremiumLegacy, llotypes.ReportFormatEVMABIEncodeUnpacked:
455+
case llotypes.ReportFormatEVMPremiumLegacy, llotypes.ReportFormatEVMABIEncodeUnpacked, llotypes.ReportFormatEVMABIEncodeUnpackedExpr:
456456
return true
457457
default:
458458
return false

llo/plugin_outcome_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,34 @@ func Test_Outcome_Methods(t *testing.T) {
822822
// if cadence is 5s, if time is < 5s, does not report because cadence hasn't elapsed
823823
require.EqualError(t, outcome.IsReportable(cid, 1, uint64(5*time.Second)), "ChannelID: 1; Reason: IsReportable=false; not valid yet (ObservationTimestampNanoseconds=1726670490999999999, validAfterNanoseconds=1726670489999999999, minReportInterval=5000000000); 4.000000 seconds (4000000000ns) until reportable")
824824
})
825+
t.Run("IsReportable with ReportFormatEVMABIEncodeUnpackedExpr prevents same-second timestamps", func(t *testing.T) {
826+
outcome := Outcome{}
827+
cid := llotypes.ChannelID(1)
828+
829+
// Test case from production bug: both timestamps truncate to same second
830+
// observationTimestampNanoseconds: 1765173183742021148 → 1765173183 sec
831+
// validAfterNanoseconds: 1765173183282997914 → 1765173183 sec
832+
outcome.LifeCycleStage = LifeCycleStageProduction
833+
outcome.ObservationTimestampNanoseconds = 1765173183742021148
834+
outcome.ChannelDefinitions = map[llotypes.ChannelID]llotypes.ChannelDefinition{
835+
cid: {ReportFormat: llotypes.ReportFormatEVMABIEncodeUnpackedExpr},
836+
}
837+
outcome.ValidAfterNanoseconds = map[llotypes.ChannelID]uint64{
838+
cid: 1765173183282997914,
839+
}
840+
841+
// Should be unreportable because timestamps are in same second
842+
require.EqualError(t, outcome.IsReportable(cid, 1, uint64(0)),
843+
"ChannelID: 1; Reason: ChannelID: 1; Reason: IsReportable=false; not valid yet (observationsTimestampSeconds=1765173183, validAfterSeconds=1765173183)")
844+
845+
// When ValidAfter is at least 1 second before observation, should be reportable
846+
outcome.ValidAfterNanoseconds[cid] = 1765173182999999999 // 1ns before previous second
847+
assert.Nil(t, outcome.IsReportable(cid, 1, uint64(0)))
848+
849+
// Test IsSecondsResolution returns true for calculated streams
850+
assert.True(t, IsSecondsResolution(llotypes.ReportFormatEVMABIEncodeUnpackedExpr),
851+
"IsSecondsResolution should return true for ReportFormatEVMABIEncodeUnpackedExpr")
852+
})
825853
t.Run("ReportableChannels", func(t *testing.T) {
826854
defaultMinReportInterval := uint64(1 * time.Second)
827855

0 commit comments

Comments
 (0)