From 17ff933151d0394dab7f23d71c22ae4edaa8759e Mon Sep 17 00:00:00 2001 From: Geert G <117188496+cll-gg@users.noreply.github.com> Date: Tue, 26 Aug 2025 13:01:39 +0100 Subject: [PATCH 1/3] DF-21546 Failing test --- .../datafeeds/securemint_aggregator_test.go | 61 ++++++++----------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator_test.go b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator_test.go index 0b0b87c286..bbd262b860 100644 --- a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator_test.go +++ b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator_test.go @@ -1,7 +1,6 @@ package datafeeds import ( - "encoding/binary" "encoding/json" "math/big" "testing" @@ -28,19 +27,20 @@ func TestSecureMintAggregator_Aggregate(t *testing.T) { lggr := logger.Test(t) tests := []struct { - name string - config *values.Map - previousOutcome *types.AggregationOutcome - observations map[ocrcommon.OracleID][]values.Value - f int - expectedShouldReport bool - expectedChainSelector chainSelector - expectError bool - errorContains string + name string + chainSelector string + dataID string + previousOutcome *types.AggregationOutcome + observations map[ocrcommon.OracleID][]values.Value + f int + expectedShouldReport bool + expectError bool + errorContains string }{ { - name: "successful eth report extraction", - config: configWithChainSelector(t, "16015286601757825753"), + name: "successful eth report extraction", + chainSelector: "16015286601757825753", // eth-testnet-sepolia + dataID: "0x01c508f42b0201320000000000000000", // test data id for a secure mint feed observations: createSecureMintObservations(t, []ocrTriggerEventData{ { chainSelector: ethSepoliaChainSelector, @@ -63,14 +63,14 @@ func TestSecureMintAggregator_Aggregate(t *testing.T) { }, }, }), - f: 1, - expectedShouldReport: true, - expectedChainSelector: ethSepoliaChainSelector, - expectError: false, + f: 1, + expectedShouldReport: true, + expectError: false, }, { - name: "no matching chain selector found", - config: configWithChainSelector(t, "16015286601757825753"), + name: "no matching chain selector found", + chainSelector: "16015286601757825753", // eth-testnet-sepolia + dataID: "0x01c508f42b0201320000000000000000", // test data id for a secure mint feed observations: createSecureMintObservations(t, []ocrTriggerEventData{ { chainSelector: bnbTestnetChainSelector, @@ -89,7 +89,8 @@ func TestSecureMintAggregator_Aggregate(t *testing.T) { }, { name: "no observations", - config: configWithChainSelector(t, "16015286601757825753"), + chainSelector: "16015286601757825753", // eth-testnet-sepolia + dataID: "0x01c508f42b0201320000000000000000", // test data id for a secure mint feed observations: map[ocrcommon.OracleID][]values.Value{}, f: 1, expectError: true, @@ -100,7 +101,12 @@ func TestSecureMintAggregator_Aggregate(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { // Create aggregator - aggregator, err := NewSecureMintAggregator(*tc.config) + configMap, err := values.WrapMap(map[string]any{ + "targetChainSelector": tc.chainSelector, + "dataID": tc.dataID, + }) + require.NoError(t, err) + aggregator, err := NewSecureMintAggregator(*configMap) require.NoError(t, err) // Run aggregation @@ -140,12 +146,7 @@ func TestSecureMintAggregator_Aggregate(t *testing.T) { // Verify dataID dataIDBytes, ok := report[DataIDOutputFieldName].([]byte) require.True(t, ok) - // Should be 0x04 + chain selector as bytes + right padded with 0s - var expectedChainSelectorBytes [16]byte - expectedChainSelectorBytes[0] = 0x04 - binary.BigEndian.PutUint64(expectedChainSelectorBytes[1:], uint64(tc.expectedChainSelector)) - require.Equal(t, expectedChainSelectorBytes[:], dataIDBytes) - t.Logf("Data ID: 0x%x", dataIDBytes) + require.Equal(t, tc.dataID, dataIDBytes) // Verify other fields exist answer, ok := report[AnswerOutputFieldName].(*big.Int) @@ -159,14 +160,6 @@ func TestSecureMintAggregator_Aggregate(t *testing.T) { } } -func configWithChainSelector(t *testing.T, chainSelector string) *values.Map { - m, err := values.NewMap(map[string]any{ - "targetChainSelector": chainSelector, - }) - require.NoError(t, err) - return m -} - func TestSecureMintAggregatorConfig_Validation(t *testing.T) { tests := []struct { name string From 109d5eb1f4047453d15e249d509ffd74efee3c74 Mon Sep 17 00:00:00 2001 From: Geert G <117188496+cll-gg@users.noreply.github.com> Date: Tue, 26 Aug 2025 13:19:34 +0100 Subject: [PATCH 2/3] Make test succeed --- .../ocr3/datafeeds/securemint_aggregator.go | 32 +++++++++++++------ .../datafeeds/securemint_aggregator_test.go | 26 ++++++++------- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go index 1221c68e78..bb40e5d3ee 100644 --- a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go +++ b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator.go @@ -1,12 +1,13 @@ package datafeeds import ( - "encoding/binary" + "encoding/hex" "encoding/json" "errors" "fmt" "math/big" "strconv" + "strings" ocrcommon "github.com/smartcontractkit/libocr/commontypes" ocr2types "github.com/smartcontractkit/libocr/offchainreporting2/types" @@ -38,6 +39,7 @@ type chainSelector uint64 type SecureMintAggregatorConfig struct { // TargetChainSelector is the chain selector to look for TargetChainSelector chainSelector `mapstructure:"targetChainSelector"` + DataID [16]byte `mapstructure:"dataID"` } // ToMap converts the SecureMintAggregatorConfig to a values.Map, which is suitable for the @@ -172,12 +174,6 @@ func (a *SecureMintAggregator) createOutcome(lggr logger.Logger, report *secureM lggr = logger.Named(lggr, "SecureMintAggregator") lggr.Debugw("createOutcome called", "report", report) - // Convert chain selector to bytes for data ID - // Secure Mint dataID: 0x04 + chain selector as bytes + right padded with 0s - var chainSelectorAsDataID [16]byte - chainSelectorAsDataID[0] = 0x04 - binary.BigEndian.PutUint64(chainSelectorAsDataID[1:], uint64(a.config.TargetChainSelector)) - 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) @@ -188,9 +184,9 @@ func (a *SecureMintAggregator) createOutcome(lggr logger.Logger, report *secureM // abi: "(bytes16 dataId, uint32 timestamp, uint224 answer)[] Reports" toWrap := []any{ map[EVMEncoderKey]any{ - DataIDOutputFieldName: chainSelectorAsDataID, + DataIDOutputFieldName: a.config.DataID, AnswerOutputFieldName: smReportAsAnswer, - TimestampOutputFieldName: int64(report.Block), + TimestampOutputFieldName: uint32(report.Block), // TODO: check if this change from int64 to uint32 is correct }, } @@ -221,6 +217,7 @@ func (a *SecureMintAggregator) createOutcome(lggr logger.Logger, report *secureM func parseSecureMintConfig(config values.Map) (SecureMintAggregatorConfig, error) { type rawConfig struct { TargetChainSelector string `mapstructure:"targetChainSelector"` + DataID string `mapstructure:"dataID"` } var rawCfg rawConfig @@ -237,8 +234,25 @@ func parseSecureMintConfig(config values.Map) (SecureMintAggregatorConfig, error return SecureMintAggregatorConfig{}, fmt.Errorf("invalid chain selector: %w", err) } + if rawCfg.DataID == "" { + return SecureMintAggregatorConfig{}, errors.New("dataID is required") + } + + // strip 0x prefix if present + dataID := strings.TrimPrefix(rawCfg.DataID, "0x") + + decodedDataID, err := hex.DecodeString(dataID) + if err != nil { + return SecureMintAggregatorConfig{}, fmt.Errorf("invalid dataID: %v %w", dataID, err) + } + + if len(decodedDataID) != 16 { + return SecureMintAggregatorConfig{}, fmt.Errorf("dataID must be 16 bytes, got %d", len(decodedDataID)) + } + parsedConfig := SecureMintAggregatorConfig{ TargetChainSelector: chainSelector(sel), + DataID: [16]byte(decodedDataID), } 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 bbd262b860..4b6f983326 100644 --- a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator_test.go +++ b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator_test.go @@ -1,6 +1,7 @@ package datafeeds import ( + "encoding/hex" "encoding/json" "math/big" "testing" @@ -114,20 +115,20 @@ func TestSecureMintAggregator_Aggregate(t *testing.T) { // Check error expectations if tc.expectError { - require.Error(t, err) + assert.Error(t, err) if tc.errorContains != "" { - require.Contains(t, err.Error(), tc.errorContains) + assert.Contains(t, err.Error(), tc.errorContains) } return } require.NoError(t, err) - require.Equal(t, tc.expectedShouldReport, outcome.ShouldReport) + assert.Equal(t, tc.expectedShouldReport, outcome.ShouldReport) if outcome.ShouldReport { // Verify the output structure matches the feeds aggregator format val, err := values.FromMapValueProto(outcome.EncodableOutcome) - require.NoError(t, err) + assert.NoError(t, err) topLevelMap, err := val.Unwrap() require.NoError(t, err) @@ -136,25 +137,26 @@ func TestSecureMintAggregator_Aggregate(t *testing.T) { // Check that we have the expected reports reportsList, ok := mm[TopLevelListOutputFieldName].([]any) - require.True(t, ok) - require.Len(t, reportsList, 1) + assert.True(t, ok) + assert.Len(t, reportsList, 1) // Check the first (and only) report report, ok := reportsList[0].(map[string]any) - require.True(t, ok) + assert.True(t, ok) // Verify dataID dataIDBytes, ok := report[DataIDOutputFieldName].([]byte) - require.True(t, ok) - require.Equal(t, tc.dataID, dataIDBytes) + assert.True(t, ok, "expected dataID to be []byte but got %T", report[DataIDOutputFieldName]) + assert.Len(t, dataIDBytes, 16) + assert.Equal(t, tc.dataID, "0x"+hex.EncodeToString(dataIDBytes)) // Verify other fields exist answer, ok := report[AnswerOutputFieldName].(*big.Int) - require.True(t, ok) - require.NotNil(t, answer) + assert.True(t, ok) + assert.NotNil(t, answer) timestamp := report[TimestampOutputFieldName].(int64) - require.Equal(t, int64(1000), timestamp) + assert.Equal(t, int64(1000), timestamp) } }) } From ead4f261843239dbe121c13675a2f3c90a97f1e2 Mon Sep 17 00:00:00 2001 From: Geert G <117188496+cll-gg@users.noreply.github.com> Date: Tue, 26 Aug 2025 13:28:13 +0100 Subject: [PATCH 3/3] Add more validation test cases --- .../datafeeds/securemint_aggregator_test.go | 81 ++++++++++++++----- 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator_test.go b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator_test.go index 4b6f983326..2541ef8b26 100644 --- a/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator_test.go +++ b/pkg/capabilities/consensus/ocr3/datafeeds/securemint_aggregator_test.go @@ -164,17 +164,37 @@ func TestSecureMintAggregator_Aggregate(t *testing.T) { func TestSecureMintAggregatorConfig_Validation(t *testing.T) { tests := []struct { - name string - chainSelector string - expected chainSelector - expectError bool - errorMsg string + name string + chainSelector string + dataID string + expectedChainSelector chainSelector + expectedDataID [16]byte + expectError bool + errorMsg string }{ { - name: "valid chain selector", - chainSelector: "1", - expected: 1, - expectError: false, + name: "valid chain selector and dataID", + chainSelector: "1", + dataID: "0x01c508f42b0201320000000000000000", + expectedChainSelector: 1, + expectedDataID: [16]byte{0x01, 0xc5, 0x08, 0xf4, 0x2b, 0x02, 0x01, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + expectError: false, + }, + { + name: "large chain selector", + chainSelector: "16015286601757825753", // ethereum-testnet-sepolia + dataID: "0x01c508f42b0201320000000000000000", + expectedChainSelector: 16015286601757825753, + expectedDataID: [16]byte{0x01, 0xc5, 0x08, 0xf4, 0x2b, 0x02, 0x01, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + expectError: false, + }, + { + name: "dataID without 0x prefix", + chainSelector: "1", + dataID: "01c508f42b0201320000000000000000", + expectedChainSelector: 1, + expectedDataID: [16]byte{0x01, 0xc5, 0x08, 0xf4, 0x2b, 0x02, 0x01, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + expectError: false, }, { name: "invalid chain selector", @@ -182,38 +202,63 @@ func TestSecureMintAggregatorConfig_Validation(t *testing.T) { expectError: true, errorMsg: "invalid chain selector", }, - { - name: "large chain selector", - chainSelector: "16015286601757825753", // ethereum-testnet-sepolia - expected: 16015286601757825753, - expectError: false, - }, { name: "negative chain selector", chainSelector: "-1", + dataID: "0x01c508f42b0201320000000000000000", expectError: true, errorMsg: "invalid chain selector", }, + { + name: "invalid dataID", + chainSelector: "1", + dataID: "invalid_data_id", + expectError: true, + errorMsg: "invalid dataID", + }, + { + name: "dataID too short", + chainSelector: "1", + dataID: "0x0000", + expectError: true, + errorMsg: "dataID must be 16 bytes", + }, + { + name: "dataID with odd length", + chainSelector: "1", + dataID: "0x0", + expectError: true, + errorMsg: "odd length hex string", + }, + { + name: "dataID too long", + chainSelector: "1", + dataID: "0x01111111111111111111111111111111111111111111", + expectError: true, + errorMsg: "dataID must be 16 bytes", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { configMap, err := values.WrapMap(map[string]any{ "targetChainSelector": tt.chainSelector, + "dataID": tt.dataID, }) require.NoError(t, err) aggregator, err := NewSecureMintAggregator(*configMap) if tt.expectError { - require.Error(t, err) + assert.Error(t, err) if tt.errorMsg != "" { - require.Contains(t, err.Error(), tt.errorMsg) + assert.Contains(t, err.Error(), tt.errorMsg) } return } require.NoError(t, err) - assert.Equal(t, tt.expected, aggregator.(*SecureMintAggregator).config.TargetChainSelector) + assert.Equal(t, tt.expectedChainSelector, aggregator.(*SecureMintAggregator).config.TargetChainSelector) + assert.Equal(t, tt.expectedDataID, aggregator.(*SecureMintAggregator).config.DataID) }) } }