Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"math/big"
"strconv"

ocrcommon "github.com/smartcontractkit/libocr/commontypes"
ocr2types "github.com/smartcontractkit/libocr/offchainreporting2/types"
Expand All @@ -31,7 +32,7 @@ type secureMintReport struct {
}

// chainSelector represents the chain selector type, mimics the ChainSelector type in the SM plugin repo
type chainSelector int64
type chainSelector uint64

// SecureMintAggregatorConfig is the config for the SecureMint aggregator.
// This aggregator is designed to pick out reports for a specific chain selector.
Expand All @@ -51,15 +52,6 @@ func (c SecureMintAggregatorConfig) ToMap() (*values.Map, error) {
return v, nil
}

func NewSecureMintConfig(m values.Map) (SecureMintAggregatorConfig, error) {
var config SecureMintAggregatorConfig
if err := m.UnwrapTo(&config); err != nil {
return SecureMintAggregatorConfig{}, fmt.Errorf("failed to unwrap values.Map %+v to SecureMintAggregatorConfig: %w", m, err)
}

return config, nil
}

var _ types.Aggregator = (*SecureMintAggregator)(nil)

type SecureMintAggregator struct {
Expand Down Expand Up @@ -241,14 +233,26 @@ func (a *SecureMintAggregator) createOutcome(lggr logger.Logger, report *secureM

// parseSecureMintConfig parses the user-facing, type-less, SecureMint aggregator config into the internal typed config.
func parseSecureMintConfig(config values.Map) (SecureMintAggregatorConfig, error) {
var parsedConfig SecureMintAggregatorConfig
if err := config.UnwrapTo(&parsedConfig); err != nil {
return SecureMintAggregatorConfig{}, fmt.Errorf("failed to unwrap config: %w", err)
type rawConfig struct {
TargetChainSelector string `mapstructure:"targetChainSelector"`
}

var rawCfg rawConfig
if err := config.UnwrapTo(&rawCfg); err != nil {
return SecureMintAggregatorConfig{}, fmt.Errorf("failed to unwrap values.Map %+v: %w", config, err)
}

if rawCfg.TargetChainSelector == "" {
return SecureMintAggregatorConfig{}, errors.New("targetChainSelector is required")
}

sel, err := strconv.ParseUint(rawCfg.TargetChainSelector, 10, 64)
if err != nil {
return SecureMintAggregatorConfig{}, fmt.Errorf("invalid chain selector: %w", err)
}

// Validate configuration
if parsedConfig.TargetChainSelector <= 0 {
return SecureMintAggregatorConfig{}, fmt.Errorf("targetChainSelector is required")
parsedConfig := SecureMintAggregatorConfig{
TargetChainSelector: chainSelector(sel),
}

return parsedConfig, nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

ocrcommon "github.com/smartcontractkit/libocr/commontypes"
ocr2types "github.com/smartcontractkit/libocr/offchainreporting2/types"
ocr3types "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"

"github.com/smartcontractkit/chainlink-common/pkg/capabilities"
"github.com/smartcontractkit/chainlink-common/pkg/capabilities/consensus/ocr3/types"
"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/values"
ocrcommon "github.com/smartcontractkit/libocr/commontypes"
ocr2types "github.com/smartcontractkit/libocr/offchainreporting2/types"
ocr3types "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
)

var (
Expand All @@ -30,7 +29,7 @@ func TestSecureMintAggregator_Aggregate(t *testing.T) {

tests := []struct {
name string
config SecureMintAggregatorConfig
config *values.Map
previousOutcome *types.AggregationOutcome
observations map[ocrcommon.OracleID][]values.Value
f int
Expand All @@ -40,10 +39,8 @@ func TestSecureMintAggregator_Aggregate(t *testing.T) {
errorContains string
}{
{
name: "successful eth report extraction",
config: SecureMintAggregatorConfig{
TargetChainSelector: ethChainSelector,
},
name: "successful eth report extraction",
config: configWithChainSelector(t, "1"),
observations: createSecureMintObservations(t, []ocrTriggerEventData{
{
chainSelector: ethChainSelector,
Expand Down Expand Up @@ -72,10 +69,8 @@ func TestSecureMintAggregator_Aggregate(t *testing.T) {
expectError: false,
},
{
name: "no matching chain selector found",
config: SecureMintAggregatorConfig{
TargetChainSelector: ethChainSelector,
},
name: "no matching chain selector found",
config: configWithChainSelector(t, "1"),
observations: createSecureMintObservations(t, []ocrTriggerEventData{
{
chainSelector: bnbChainSelector,
Expand All @@ -93,10 +88,8 @@ func TestSecureMintAggregator_Aggregate(t *testing.T) {
expectedShouldReport: false,
},
{
name: "sequence number too low",
config: SecureMintAggregatorConfig{
TargetChainSelector: ethChainSelector,
},
name: "sequence number too low",
config: configWithChainSelector(t, "1"),
previousOutcome: &types.AggregationOutcome{
LastSeenAt: 10, // Previous sequence number
},
Expand All @@ -117,20 +110,16 @@ func TestSecureMintAggregator_Aggregate(t *testing.T) {
errorContains: "sequence number too low",
},
{
name: "no observations",
config: SecureMintAggregatorConfig{
TargetChainSelector: ethChainSelector,
},
name: "no observations",
config: configWithChainSelector(t, "1"),
observations: map[ocrcommon.OracleID][]values.Value{},
f: 1,
expectError: true,
errorContains: "no observations",
},
{
name: "sequence number equal to previous (should be ignored)",
config: SecureMintAggregatorConfig{
TargetChainSelector: ethChainSelector,
},
name: "sequence number equal to previous (should be ignored)",
config: configWithChainSelector(t, "1"),
previousOutcome: &types.AggregationOutcome{
LastSeenAt: 10, // Previous sequence number
},
Expand All @@ -154,12 +143,8 @@ func TestSecureMintAggregator_Aggregate(t *testing.T) {

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
// Create config map
cfgMap, err := tc.config.ToMap()
require.NoErrorf(t, err, "Failed to convert config %+v to values.Map", tc.config)

// Create aggregator
aggregator, err := NewSecureMintAggregator(*cfgMap)
aggregator, err := NewSecureMintAggregator(*tc.config)
require.NoError(t, err)

// Run aggregation
Expand Down Expand Up @@ -220,95 +205,66 @@ func TestSecureMintAggregator_Aggregate(t *testing.T) {
}
}

func TestSecureMintAggregatorConfig_RoundTrip(t *testing.T) {
testCases := []struct {
name string
config SecureMintAggregatorConfig
}{
{
name: "default eth config",
config: SecureMintAggregatorConfig{
TargetChainSelector: ethChainSelector,
},
},
{
name: "custom target chain selector",
config: SecureMintAggregatorConfig{
TargetChainSelector: bnbChainSelector,
},
},
{
name: "large chain selector",
config: SecureMintAggregatorConfig{
TargetChainSelector: 999999,
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Step 1: Convert original config to values.Map
configMap, err := tc.config.ToMap()
require.NoError(t, err, "ToMap should not error")
require.NotNil(t, configMap, "ToMap should return non-nil map")

// Step 2: Convert values.Map back to config
roundTrippedConfig, err := NewSecureMintConfig(*configMap)
require.NoError(t, err, "NewSecureMintConfig should not error")

// Step 3: Compare original and round-tripped configs
assert.Equal(t, tc.config.TargetChainSelector, roundTrippedConfig.TargetChainSelector,
"TargetChainSelector should match")
})
}
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
config SecureMintAggregatorConfig
expectError bool
errorMsg string
name string
chainSelector string
expected chainSelector
expectError bool
errorMsg string
}{
{
name: "valid config",
config: SecureMintAggregatorConfig{
TargetChainSelector: ethChainSelector,
},
expectError: false,
name: "valid chain selector",
chainSelector: "1",
expected: 1,
expectError: false,
},
{
name: "zero target chain selector",
config: SecureMintAggregatorConfig{
TargetChainSelector: 0,
},
expectError: true,
errorMsg: "targetChainSelector is required",
name: "invalid chain selector",
chainSelector: "invalid",
expectError: true,
errorMsg: "invalid chain selector",
},
{
name: "negative chain selector",
config: SecureMintAggregatorConfig{
TargetChainSelector: -1,
},
expectError: true,
errorMsg: "targetChainSelector is required",
name: "large chain selector",
chainSelector: "16015286601757825753", // ethereum-testnet-sepolia
expected: 16015286601757825753,
expectError: false,
},
{
name: "negative chain selector",
chainSelector: "-1",
expectError: true,
errorMsg: "invalid chain selector",
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
configMap, err := tc.config.ToMap()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
configMap, err := values.WrapMap(map[string]any{
"targetChainSelector": tt.chainSelector,
})
require.NoError(t, err)

_, err = NewSecureMintAggregator(*configMap)
if tc.expectError {
aggregator, err := NewSecureMintAggregator(*configMap)
if tt.expectError {
require.Error(t, err)
if tc.errorMsg != "" {
require.Contains(t, err.Error(), tc.errorMsg)
if tt.errorMsg != "" {
require.Contains(t, err.Error(), tt.errorMsg)
}
} else {
require.NoError(t, err)
return
}

require.NoError(t, err)
assert.Equal(t, tt.expected, aggregator.(*SecureMintAggregator).config.TargetChainSelector)
})
}
}
Expand Down
Loading