llo

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 14, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package llo: outcome_golden_cases.go defines golden outcome cases for outcome serialization tests.

Index

Constants

View Source
const (
	// NOTE: CAREFUL! If we ever accidentally exceed these e.g.
	// through too many channels/streams, the protocol will halt.
	MaxObservationLength = ocr3types.MaxMaxObservationLength
	MaxOutcomeLength     = ocr3types.MaxMaxOutcomeLength
	MaxReportLength      = ocr3types.MaxMaxReportLength
)

OCR3.0 transport limits, reported in the v3.0 ReportingPluginInfo. The LLO-protocol limits (MaxReportCount, MaxObservation*Length, MaxStreamsPerChannel, MaxOutcomeChannelDefinitionsLength) are shared across plugin versions and live in the root llo package (limits.go).

Variables

This section is empty.

Functions

func IsSecondsResolution

func IsSecondsResolution(cd llocommon.ChannelDefinitionWithID, optsCache *llocommon.OptsCache) bool

IsSecondsResolution returns whether the report format uses second-level resolution for the given opts. For ReportFormatEVMABIEncodeUnpacked, the cache must be populated (e.g. by Outcome's reset or Set during channel add/update) for correct resolution; no fallback to decoding opts is used — on cache miss it returns false.

func MakeChannelHash

MakeChannelHash is used for mapping ChannelDefinitionWithIDs

func StreamAggregatesToProtoOutcome

func StreamAggregatesToProtoOutcome(in llocommon.StreamAggregates) (out []*llocommon.LLOStreamAggregate, err error)

Types

type Config

type Config struct {
	// Enables additional logging that might be expensive, e.g. logging entire
	// channel definitions on every round or other very large structs
	VerboseLogging bool
}

type DSOpts

type DSOpts interface {
	VerboseLogging() bool
	SeqNr() uint64
	OutCtx() ocr3types.OutcomeContext
	ConfigDigest() ocr2types.ConfigDigest
	ObservationTimestamp() time.Time
	OutcomeCodec() OutcomeCodec
}

type DataSource

type DataSource interface {
	// For each known streamID, Observe should set the observed value in the
	// passed streamValues.
	// If an observation fails, or the stream is unknown, no value should be
	// set.
	Observe(ctx context.Context, streamValues llocommon.StreamValues, opts DSOpts) error
}

type GoldenOutcomeCase

type GoldenOutcomeCase struct {
	Name       string
	Outcome    Outcome
	OutputFile string
}

GoldenOutcomeCase defines a single outcome serialization golden test case. Used by llo/tools/generate_golden to emit golden files and by outcome_codec_v1_test for comparison.

func GoldenOutcomeCases

func GoldenOutcomeCases() []GoldenOutcomeCase

GoldenOutcomeCases returns the canonical set of outcome golden cases. "initial" and "from_full" are outcomes the plugin produces (Plugin.Outcome); "full" is a fixture used as previous outcome to produce "from_full".

type Observation

type Observation struct {
	// Attested (i.e. signed by f+1 oracles) retirement report from predecessor
	// protocol instance
	AttestedPredecessorRetirement []byte
	// Should this protocol instance be retired?
	ShouldRetire bool
	// Timestamp from when observation is made
	// Note that this is the timestamp immediately before we initiate any
	// observations
	UnixTimestampNanoseconds uint64
	// Votes to remove/add channels. Subject to MAX_OBSERVATION_*_LENGTH limits
	RemoveChannelIDs map[llotypes.ChannelID]struct{}
	// Votes to add or replace channel definitions
	UpdateChannelDefinitions llotypes.ChannelDefinitions
	// Observed (numeric) stream values. Subject to
	// MaxObservationStreamValuesLength limit
	StreamValues llocommon.StreamValues
}

type ObservationCodec

type ObservationCodec interface {
	Encode(obs Observation) (types.Observation, error)
	Decode(encoded types.Observation) (obs Observation, err error)
}

func NewProtoObservationCodec

func NewProtoObservationCodec(lggr logger.Logger, enableCompression bool) (ObservationCodec, error)

type Outcome

type Outcome struct {
	// LifeCycleStage the protocol is in
	LifeCycleStage llotypes.LifeCycleStage
	// ObservationTimestampNanoseconds is the median timestamp from the
	// latest set of observations
	ObservationTimestampNanoseconds uint64
	// ChannelDefinitions defines the set & structure of channels for which we
	// generate reports
	ChannelDefinitions llotypes.ChannelDefinitions
	// Latest ValidAfterNanoseconds value for each channel, reports for each channel
	// span from ValidAfterNanoseconds to ObservationTimestampNanoseconds
	ValidAfterNanoseconds map[llotypes.ChannelID]uint64
	// StreamAggregates contains stream IDs mapped to various aggregations.
	// Usually you will only have one aggregation type per stream but since
	// channels can define different aggregation methods, sometimes we will
	// need multiple.
	StreamAggregates llocommon.StreamAggregates
}

func (*Outcome) GenRetirementReport

func (out *Outcome) GenRetirementReport(protocolVersion uint32) llocommon.RetirementReport

func (*Outcome) IsReportable

func (out *Outcome) IsReportable(channelID llotypes.ChannelID, protocolVersion uint32, minReportInterval uint64, optsCache *llocommon.OptsCache) *UnreportableChannelError

IsReportable checks if a report can be generated for the given channel. Checks if channel is retired, tombstoned, has missing stream values (when DisableNilStreamValues is true), and if ValidAfterNanoseconds is set. Returns nil if channel is reportable. Time-resolution for overlap checks uses IsSecondsResolution, which tries the cache when available and falls back to decoding opts (e.g. after node restart).

Note: this is not a complete guarantee that a report will be successfully generated. Reports can still be silently dropped at the encoding step for other reasons (e.g. codec errors, bid/mid/ask validation failures). Those failure modes are not covered here and can still result in report gaps if DisableNilStreamValues is false or if the report codec fails to encode the report.

func (*Outcome) ReportableChannels

func (out *Outcome) ReportableChannels(protocolVersion uint32, defaultMinReportInterval uint64, optsCache *llocommon.OptsCache) (reportable []llotypes.ChannelID, unreportable []*UnreportableChannelError)

ReportableChannels returns a sorted list of reportable channel IDs and errors for unreportable ones.

type OutcomeCodec

type OutcomeCodec interface {
	Encode(outcome Outcome) (ocr3types.Outcome, error)
	Decode(encoded ocr3types.Outcome) (outcome Outcome, err error)
}

func GetOutcomeCodec

func GetOutcomeCodec(c llocommon.OffchainConfig) OutcomeCodec

GetOutcomeCodec selects the outcome codec for the given offchain config's protocol version. It is a free function (rather than a method on the shared OffchainConfig type) because the outcome codecs are v3.0-specific.

type Plugin

type Plugin struct {
	Config                           Config
	PredecessorConfigDigest          *types.ConfigDigest
	ConfigDigest                     types.ConfigDigest
	PredecessorRetirementReportCache llocommon.PredecessorRetirementReportCache
	ShouldRetireCache                ShouldRetireCache
	ChannelDefinitionCache           llotypes.ChannelDefinitionCache
	DataSource                       DataSource
	Logger                           logger.Logger
	N                                int
	F                                int
	ObservationCodec                 ObservationCodec
	OutcomeCodec                     OutcomeCodec
	RetirementReportCodec            llocommon.RetirementReportCodec
	ReportCodecs                     map[llotypes.ReportFormat]llocommon.ReportCodec
	OutcomeTelemetryCh               chan<- *llocommon.LLOOutcomeTelemetry
	ReportTelemetryCh                chan<- *llocommon.LLOReportTelemetry
	DonID                            uint32
	OptsCache                        *llocommon.OptsCache // must be non-nil; set by NewReportingPlugin or by tests that exercise Outcome/Reports

	// From ReportingPluginConfig
	MaxDurationObservation time.Duration

	// From offchain config
	ProtocolVersion                     uint32
	DefaultMinReportIntervalNanoseconds uint64
}

func (*Plugin) Close

func (p *Plugin) Close() error

func (*Plugin) Observation

func (p *Plugin) Observation(ctx context.Context, outctx ocr3types.OutcomeContext, query types.Query) (types.Observation, error)

Observation gets an observation from the underlying data source. Returns a value or an error.

You may assume that the outctx.SeqNr is increasing monotonically (though *not* strictly) across the lifetime of a protocol instance and that outctx.previousOutcome contains the consensus outcome with sequence number (outctx.SeqNr-1).

Should return a serialized Observation struct.

func (*Plugin) ObservationQuorum

func (p *Plugin) ObservationQuorum(ctx context.Context, outctx ocr3types.OutcomeContext, query types.Query, aos []types.AttributedObservation) (bool, error)

ObservationQuorum returns the minimum number of valid (according to ValidateObservation) observations needed to construct an outcome.

This function should be pure. Don't do anything slow in here.

This is an advanced feature. The "default" approach (what OCR1 & OCR2 did) is to have an empty ValidateObservation function and return QuorumTwoFPlusOne from this function.

func (*Plugin) Outcome

Generates an outcome for a seqNr, typically based on the previous outcome, the current query, and the current set of attributed observations.

This function should be pure. Don't do anything slow in here.

You may assume that the outctx.SeqNr is increasing monotonically (though *not* strictly) across the lifetime of a protocol instance and that outctx.previousOutcome contains the consensus outcome with sequence number (outctx.SeqNr-1).

libocr guarantees that this will always be called with at least 2f+1 AttributedObservations

func (*Plugin) ProcessCalculatedStreams

func (p *Plugin) ProcessCalculatedStreams(outcome *Outcome)

ProcessCalculatedStreams evaluates calculated-stream expressions for the outcome's EVMABIEncodeUnpackedExpr channels, appending the calculated streams to their channel definitions and writing the evaluated values into the outcome's StreamAggregates.

func (*Plugin) ProcessCalculatedStreamsDryRun

func (p *Plugin) ProcessCalculatedStreamsDryRun(expression string) error

ProcessCalculatedStreamsDryRun validates an expression against synthetic inputs.

func (*Plugin) Query

func (p *Plugin) Query(ctx context.Context, outctx ocr3types.OutcomeContext) (types.Query, error)

Query creates a Query that is sent from the leader to all follower nodes as part of the request for an observation. Be careful! A malicious leader could equivocate (i.e. send different queries to different followers.) Many applications will likely be better off always using an empty query if the oracles don't need to coordinate on what to observe (e.g. in case of a price feed) or the underlying data source offers an (eventually) consistent view to different oracles (e.g. in case of observing a blockchain).

You may assume that the outctx.SeqNr is increasing monotonically (though *not* strictly) across the lifetime of a protocol instance and that outctx.previousOutcome contains the consensus outcome with sequence number (outctx.SeqNr-1).

func (*Plugin) Reports

func (p *Plugin) Reports(ctx context.Context, seqNr uint64, rawOutcome ocr3types.Outcome) ([]ocr3types.ReportPlus[llotypes.ReportInfo], error)

Generates a (possibly empty) list of reports from an outcome. Each report will be signed and possibly be transmitted to the contract. (Depending on ShouldAcceptAttestedReport & ShouldTransmitAcceptedReport)

This function should be pure. Don't do anything slow in here.

This is likely to change in the future. It will likely be returning a list of report batches, where each batch goes into its own Merkle tree.

You may assume that the outctx.SeqNr is increasing monotonically (though *not* strictly) across the lifetime of a protocol instance and that outctx.previousOutcome contains the consensus outcome with sequence number (outctx.SeqNr-1).

func (*Plugin) ShouldAcceptAttestedReport

func (p *Plugin) ShouldAcceptAttestedReport(context.Context, uint64, ocr3types.ReportWithInfo[llotypes.ReportInfo]) (bool, error)

func (*Plugin) ShouldTransmitAcceptedReport

func (p *Plugin) ShouldTransmitAcceptedReport(context.Context, uint64, ocr3types.ReportWithInfo[llotypes.ReportInfo]) (bool, error)

func (*Plugin) ValidateObservation

func (p *Plugin) ValidateObservation(ctx context.Context, outctx ocr3types.OutcomeContext, query types.Query, ao types.AttributedObservation) error

Should return an error if an observation isn't well-formed. Non-well-formed observations will be discarded by the protocol. This is called for each observation, don't do anything slow in here.

You may assume that the outctx.SeqNr is increasing monotonically (though *not* strictly) across the lifetime of a protocol instance and that outctx.previousOutcome contains the consensus outcome with sequence number (outctx.SeqNr-1).

type PluginFactoryParams

type PluginFactoryParams struct {
	Config
	llocommon.PredecessorRetirementReportCache
	ShouldRetireCache
	llocommon.RetirementReportCodec
	llotypes.ChannelDefinitionCache
	DataSource
	logger.Logger
	llocommon.OnchainConfigCodec
	ReportCodecs map[llotypes.ReportFormat]llocommon.ReportCodec
	// LLOOutcomeTelemetryCh if set will be used to send one telemetry struct per
	// round in the Outcome stage
	OutcomeTelemetryCh chan<- *llocommon.LLOOutcomeTelemetry
	// ReportTelemetryCh if set will be used to send one telemetry struct per
	// transmissible report in the Report stage
	ReportTelemetryCh chan<- *llocommon.LLOReportTelemetry
	// DonID is optional and used only for telemetry and logging
	DonID uint32
}

type ShouldRetireCache

type ShouldRetireCache interface {
	// Should the protocol instance retire according to the configuration
	// contract?
	// See: https://github.com/smartcontractkit/mercury-v1-sketch/blob/main/onchain/src/ConfigurationStore.sol#L18
	ShouldRetire(digest ocr2types.ConfigDigest) (bool, error)
}

type UnreportableChannelError

type UnreportableChannelError struct {
	Inner     error `json:",omitempty"`
	Reason    string
	ChannelID llotypes.ChannelID
}

func SelectBackfillCandidate

func SelectBackfillCandidate(out *Outcome, backfillCID llotypes.ChannelID) (tsNanos uint64, rawTS uint64, opts llocommon.HistoryBackfillOpts, uerr *UnreportableChannelError)

SelectBackfillCandidate returns the next observation timestamp in nanoseconds, its raw key, and parsed opts, or an UnreportableChannelError. outcome.ValidAfterNanoseconds[backfillCID] is the progress watermark (last emitted backfill observation time, in nanoseconds). Min report interval and second-resolution overlap rules used for live channels do not apply to history_backfill.

func (*UnreportableChannelError) Error

func (e *UnreportableChannelError) Error() string

func (*UnreportableChannelError) String

func (e *UnreportableChannelError) String() string

func (*UnreportableChannelError) Unwrap

func (e *UnreportableChannelError) Unwrap() error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL