From d3606fe4a58770036b194ce497f621f516a0218c Mon Sep 17 00:00:00 2001 From: Vladimir Shchukin Date: Tue, 2 Sep 2025 08:09:31 -0400 Subject: [PATCH 1/5] add account context to observations --- .../ocr3/datafeeds/securemint_aggregator.go | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go index 9c12b3b6d..83e821c29 100644 --- a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go +++ b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go @@ -62,10 +62,11 @@ const ( // secureMintReport represents the inner report structure, mimics the Report type in the SM plugin repo type secureMintReport struct { - ConfigDigest ocr2types.ConfigDigest `json:"configDigest"` - SeqNr uint64 `json:"seqNr"` - Block uint64 `json:"block"` - Mintable *big.Int `json:"mintable"` + ConfigDigest ocr2types.ConfigDigest `json:"configDigest"` + SeqNr uint64 `json:"seqNr"` + Block uint64 `json:"block"` + Mintable *big.Int `json:"mintable"` + AccountContext solana.AccountMetaSlice `json:"-"` } // chainSelector represents the chain selector type, mimics the ChainSelector type in the SM plugin repo @@ -303,11 +304,19 @@ func (a *SecureMintAggregator) extractAndValidateReports(lggr logger.Logger, obs lggr.Debugw("processing observation", "observation", observation) // Extract OCRTriggerEvent from the observation - triggerEvent := &capabilities.OCRTriggerEvent{} - if err := observation.UnwrapTo(triggerEvent); err != nil { + type ObsWithCtx struct { + Event *capabilities.OCRTriggerEvent `mapstructure:"event"` + Solana *struct { + RemainingAccounts solana.AccountMetaSlice `mapstructure:"remaining_accounts"` + } `mapstructure:"solana"` + } + obsWithContext := &ObsWithCtx{} + + if err := observation.UnwrapTo(obsWithContext); err != nil { lggr.Warnw("could not unwrap OCRTriggerEvent", "err", err, "observation", observation) continue } + triggerEvent := obsWithContext.Event lggr.Debugw("triggerEvent", "triggerEvent", triggerEvent) @@ -333,6 +342,7 @@ func (a *SecureMintAggregator) extractAndValidateReports(lggr logger.Logger, obs lggr.Errorw("failed to unmarshal secureMintReport", "err", err) continue } + innerReport.AccountContext = obsWithContext.Solana.RemainingAccounts validReports = append(validReports, &innerReport) } From 38adb08342bdfcc7b0eed62653992cf55fdef12f Mon Sep 17 00:00:00 2001 From: Vladimir Shchukin Date: Tue, 2 Sep 2025 08:24:42 -0400 Subject: [PATCH 2/5] change report structure --- .../consensus/ocr3/datafeeds/securemint_aggregator.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go index 83e821c29..26eeba7f9 100644 --- a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go +++ b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go @@ -305,11 +305,10 @@ func (a *SecureMintAggregator) extractAndValidateReports(lggr logger.Logger, obs // Extract OCRTriggerEvent from the observation type ObsWithCtx struct { - Event *capabilities.OCRTriggerEvent `mapstructure:"event"` - Solana *struct { - RemainingAccounts solana.AccountMetaSlice `mapstructure:"remaining_accounts"` - } `mapstructure:"solana"` + Event capabilities.OCRTriggerEvent `mapstructure:"event"` + Solana solana.AccountMetaSlice `mapstructure:"solana"` } + obsWithContext := &ObsWithCtx{} if err := observation.UnwrapTo(obsWithContext); err != nil { @@ -342,7 +341,7 @@ func (a *SecureMintAggregator) extractAndValidateReports(lggr logger.Logger, obs lggr.Errorw("failed to unmarshal secureMintReport", "err", err) continue } - innerReport.AccountContext = obsWithContext.Solana.RemainingAccounts + innerReport.AccountContext = obsWithContext.Solana validReports = append(validReports, &innerReport) } From a09f951843727f139d6c546504a853542e425534 Mon Sep 17 00:00:00 2001 From: Vladimir Shchukin Date: Tue, 2 Sep 2025 08:35:49 -0400 Subject: [PATCH 3/5] add debug log --- .../consensus/ocr3/datafeeds/securemint_aggregator.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go index 26eeba7f9..c270098fb 100644 --- a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go +++ b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go @@ -317,6 +317,8 @@ func (a *SecureMintAggregator) extractAndValidateReports(lggr logger.Logger, obs } triggerEvent := obsWithContext.Event + lggr.Debugw("Meta slice", obsWithContext.Solana) + lggr.Debugw("triggerEvent", "triggerEvent", triggerEvent) // Deserialize the ReportWithInfo From 7fc8a1e081b1acf63f0cbcef02b94ca6c37d1f18 Mon Sep 17 00:00:00 2001 From: Vladimir Shchukin Date: Tue, 2 Sep 2025 09:01:32 -0400 Subject: [PATCH 4/5] pass context through observations --- .../ocr3/datafeeds/securemint_aggregator.go | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go index c270098fb..13e6128cd 100644 --- a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go +++ b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go @@ -69,6 +69,11 @@ type secureMintReport struct { AccountContext solana.AccountMetaSlice `json:"-"` } +type wrappedMintReport struct { + report secureMintReport `json:"report"` + solanaAccountContext solana.AccountMetaSlice `json:"solanaAccountContext"` +} + // chainSelector represents the chain selector type, mimics the ChainSelector type in the SM plugin repo type chainSelector uint64 @@ -105,7 +110,7 @@ type SecureMintAggregator struct { } type chainReportFormatter interface { - packReport(lggr logger.Logger, report *secureMintReport) (*values.Map, error) + packReport(lggr logger.Logger, report *wrappedMintReport) (*values.Map, error) } type evmReportFormatter struct { @@ -113,7 +118,8 @@ type evmReportFormatter struct { dataID [16]byte } -func (f *evmReportFormatter) packReport(lggr logger.Logger, report *secureMintReport) (*values.Map, error) { +func (f *evmReportFormatter) packReport(lggr logger.Logger, wreport *wrappedMintReport) (*values.Map, error) { + report := wreport.report smReportAsAnswer, err := packSecureMintReportIntoUint224ForEVM(report.Mintable, report.Block) if err != nil { return nil, fmt.Errorf("failed to pack secure mint report for evm into uint224: %w", err) @@ -151,7 +157,8 @@ type solanaReportFormatter struct { onReportAccounts solana.AccountMetaSlice } -func (f *solanaReportFormatter) packReport(lggr logger.Logger, report *secureMintReport) (*values.Map, error) { +func (f *solanaReportFormatter) packReport(lggr logger.Logger, wreport *wrappedMintReport) (*values.Map, error) { + report := wreport.report // pack answer smReportAsAnswer, err := packSecureMintReportIntoU128ForSolana(report.Mintable, report.Block) if err != nil { @@ -161,9 +168,10 @@ func (f *solanaReportFormatter) packReport(lggr logger.Logger, report *secureMin // hash account contexts var accounts = make([]byte, 0) - for _, acc := range f.onReportAccounts { + for _, acc := range wreport.solanaAccountContext { accounts = append(accounts, acc.PublicKey[:]...) } + lggr.Debugf("accounts length: %d", len(accounts)) accountContextHash := sha256.Sum256(accounts) lggr.Debugw("calculated account context hash", "accountContextHash", accountContextHash) @@ -293,8 +301,8 @@ func (a *SecureMintAggregator) Aggregate(lggr logger.Logger, previousOutcome *ty } // extractAndValidateReports extracts OCRTriggerEvent from observations and validates them -func (a *SecureMintAggregator) extractAndValidateReports(lggr logger.Logger, observations map[ocrcommon.OracleID][]values.Value, previousOutcome *types.AggregationOutcome) ([]*secureMintReport, error) { - var validReports []*secureMintReport +func (a *SecureMintAggregator) extractAndValidateReports(lggr logger.Logger, observations map[ocrcommon.OracleID][]values.Value, previousOutcome *types.AggregationOutcome) ([]*wrappedMintReport, error) { + var validReports []*wrappedMintReport var foundMatchingChainSelector bool for nodeID, nodeObservations := range observations { @@ -317,7 +325,7 @@ func (a *SecureMintAggregator) extractAndValidateReports(lggr logger.Logger, obs } triggerEvent := obsWithContext.Event - lggr.Debugw("Meta slice", obsWithContext.Solana) + lggr.Debugw("Obs with context", "obs with ctx", obsWithContext) lggr.Debugw("triggerEvent", "triggerEvent", triggerEvent) @@ -343,9 +351,12 @@ func (a *SecureMintAggregator) extractAndValidateReports(lggr logger.Logger, obs lggr.Errorw("failed to unmarshal secureMintReport", "err", err) continue } - innerReport.AccountContext = obsWithContext.Solana + report := &wrappedMintReport{ + report: innerReport, + solanaAccountContext: obsWithContext.Solana, + } - validReports = append(validReports, &innerReport) + validReports = append(validReports, report) } } @@ -359,7 +370,7 @@ func (a *SecureMintAggregator) extractAndValidateReports(lggr logger.Logger, obs } // createOutcome creates the final aggregation outcome which can be sent to the KeystoneForwarder -func (a *SecureMintAggregator) createOutcome(lggr logger.Logger, report *secureMintReport) (*types.AggregationOutcome, error) { +func (a *SecureMintAggregator) createOutcome(lggr logger.Logger, report *wrappedMintReport) (*types.AggregationOutcome, error) { lggr = logger.Named(lggr, "SecureMintAggregator") lggr.Debugw("createOutcome called", "report", report) @@ -380,12 +391,12 @@ func (a *SecureMintAggregator) createOutcome(lggr logger.Logger, report *secureM reportsProto := values.Proto(wrappedReport) // Store the sequence number in metadata for next round - metadata := []byte{byte(report.SeqNr)} // Simple metadata for now + metadata := []byte{byte(report.report.SeqNr)} // Simple metadata for now aggOutcome := &types.AggregationOutcome{ EncodableOutcome: reportsProto.GetMapValue(), Metadata: metadata, - LastSeenAt: report.SeqNr, + LastSeenAt: report.report.SeqNr, ShouldReport: true, // Always report since we found and verified the target report } From 2f85357cd094f475cc9763f9b9b361ff0b2676e8 Mon Sep 17 00:00:00 2001 From: Vladimir Shchukin Date: Tue, 2 Sep 2025 09:28:48 -0400 Subject: [PATCH 5/5] log passed dataID --- .../ocr3/datafeeds/securemint_aggregator.go | 26 ++++--------------- .../datafeeds/securemint_aggregator_test.go | 1 - 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go index 13e6128cd..d23f66f1f 100644 --- a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go +++ b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go @@ -77,18 +77,12 @@ type wrappedMintReport struct { // chainSelector represents the chain selector type, mimics the ChainSelector type in the SM plugin repo type chainSelector uint64 -type SolanaConfig struct { - // Add Solana-specific configuration fields here - AccountContext solana.AccountMetaSlice `mapstructure:"remaining_accounts"` -} - // SecureMintAggregatorConfig is the config for the SecureMint aggregator. // This aggregator is designed to pick out reports for a specific chain selector. type SecureMintAggregatorConfig struct { // TargetChainSelector is the chain selector to look for TargetChainSelector chainSelector `mapstructure:"targetChainSelector"` DataID [16]byte `mapstructure:"dataID"` - Solana SolanaConfig `mapstructure:"solana"` } // ToMap converts the SecureMintAggregatorConfig to a values.Map, which is suitable for the @@ -154,7 +148,6 @@ func newEVMReportFormatter(chainSelector chainSelector, config SecureMintAggrega type solanaReportFormatter struct { targetChainSelector chainSelector dataID [16]byte - onReportAccounts solana.AccountMetaSlice } func (f *solanaReportFormatter) packReport(lggr logger.Logger, wreport *wrappedMintReport) (*values.Map, error) { @@ -171,7 +164,7 @@ func (f *solanaReportFormatter) packReport(lggr logger.Logger, wreport *wrappedM for _, acc := range wreport.solanaAccountContext { accounts = append(accounts, acc.PublicKey[:]...) } - lggr.Debugf("accounts length: %d", len(accounts)) + lggr.Debugf("accounts length: %d", len(wreport.solanaAccountContext)) accountContextHash := sha256.Sum256(accounts) lggr.Debugw("calculated account context hash", "accountContextHash", accountContextHash) @@ -186,6 +179,7 @@ func (f *solanaReportFormatter) packReport(lggr logger.Logger, wreport *wrappedM SolDataIDOutputFieldName: f.dataID, }, } + lggr.Debugf("pass dataID %x", f.dataID) wrappedReport, err := values.NewMap(map[string]any{ TopLevelAccountCtxHashFieldName: accountContextHash, @@ -200,7 +194,7 @@ func (f *solanaReportFormatter) packReport(lggr logger.Logger, wreport *wrappedM } func newSolanaReportFormatter(chainSelector chainSelector, config SecureMintAggregatorConfig) chainReportFormatter { - return &solanaReportFormatter{targetChainSelector: chainSelector, onReportAccounts: config.Solana.AccountContext, dataID: config.DataID} + return &solanaReportFormatter{targetChainSelector: chainSelector, dataID: config.DataID} } // chainReportFormatterBuilder is a function that returns a chainReportFormatter for a given chain selector and config @@ -407,9 +401,8 @@ func (a *SecureMintAggregator) createOutcome(lggr logger.Logger, report *wrapped // parseSecureMintConfig parses the user-facing, type-less, SecureMint aggregator config into the internal typed config. func parseSecureMintConfig(config values.Map) (SecureMintAggregatorConfig, error) { type rawConfig struct { - TargetChainSelector string `mapstructure:"targetChainSelector"` - DataID string `mapstructure:"dataID"` - Solana SolanaConfig `mapstructure:"solana"` + TargetChainSelector string `mapstructure:"targetChainSelector"` + DataID string `mapstructure:"dataID"` } var rawCfg rawConfig @@ -442,18 +435,9 @@ func parseSecureMintConfig(config values.Map) (SecureMintAggregatorConfig, error return SecureMintAggregatorConfig{}, fmt.Errorf("dataID must be 16 bytes, got %d", len(decodedDataID)) } - if len(rawCfg.Solana.AccountContext) > 0 { - for _, acc := range rawCfg.Solana.AccountContext { - if acc.PublicKey == [32]byte{} { - return SecureMintAggregatorConfig{}, errors.New("solana account context public key must not be all zeros") - } - } - } - parsedConfig := SecureMintAggregatorConfig{ TargetChainSelector: chainSelector(sel), DataID: [16]byte(decodedDataID), - Solana: rawCfg.Solana, } return parsedConfig, nil diff --git a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator_test.go b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator_test.go index da871d80a..6fc5fd338 100644 --- a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator_test.go +++ b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator_test.go @@ -373,7 +373,6 @@ func TestSecureMintAggregatorConfig_Validation(t *testing.T) { require.NoError(t, err) assert.Equal(t, tt.expectedChainSelector, aggregator.(*SecureMintAggregator).config.TargetChainSelector) assert.Equal(t, tt.expectedDataID, aggregator.(*SecureMintAggregator).config.DataID) - assert.Equal(t, tt.solanaAccounts, aggregator.(*SecureMintAggregator).config.Solana.AccountContext) }) } }