From 4addc489a3796ffbf7d1371d430610a91bb324ed Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Mon, 30 Dec 2024 12:32:25 -0500 Subject: [PATCH 01/14] CCIP-4703: Adding check for ChainFeeUpdates field --- commit/chainfee/validate_observation.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/commit/chainfee/validate_observation.go b/commit/chainfee/validate_observation.go index f498a94a5..0edc73e7d 100644 --- a/commit/chainfee/validate_observation.go +++ b/commit/chainfee/validate_observation.go @@ -50,5 +50,15 @@ func (p *processor) ValidateObservation( } } + for _, update := range obs.ChainFeeUpdates { + if update.ChainFee.ExecutionFeePriceUSD == nil || update.ChainFee.ExecutionFeePriceUSD.Cmp(zero) <= 0 { + return fmt.Errorf("nil or non-positive %s", "execution fee price") + } + + if update.ChainFee.DataAvFeePriceUSD == nil || update.ChainFee.DataAvFeePriceUSD.Cmp(zero) < 0 { + return fmt.Errorf("nil or negative %s", "data availability fee price") + } + } + return nil } From 5bcb9b8b3f5a6eb9b6f8c07953446e63b176db45 Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Tue, 31 Dec 2024 11:15:09 -0500 Subject: [PATCH 02/14] Separating observed chains validation --- commit/chainfee/validate_observation.go | 34 +++++++++++++++++-------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/commit/chainfee/validate_observation.go b/commit/chainfee/validate_observation.go index 0edc73e7d..8ef23c5c1 100644 --- a/commit/chainfee/validate_observation.go +++ b/commit/chainfee/validate_observation.go @@ -2,6 +2,7 @@ package chainfee import ( "fmt" + "github.com/pkg/errors" "math/big" "github.com/smartcontractkit/chainlink-ccip/internal/plugincommon" @@ -21,17 +22,8 @@ func (p *processor) ValidateObservation( return fmt.Errorf("failed to validate FChain: %w", err) } - observerSupportedChains, err := p.chainSupport.SupportedChains(ao.OracleID) - if err != nil { - return fmt.Errorf("failed to get supported chains: %w", err) - } - - observedChains := append(maps.Keys(obs.FeeComponents), maps.Keys(obs.NativeTokenPrices)...) - - for _, chain := range observedChains { - if !observerSupportedChains.Contains(chain) { - return fmt.Errorf("chain %d is not supported by observer", chain) - } + if err := p.ValidateObservedChains(ao); err != nil { + return errors.Wrap(err, "failed to validate observed chains") } for _, feeComponent := range obs.FeeComponents { @@ -62,3 +54,23 @@ func (p *processor) ValidateObservation( return nil } + +func (p *processor) ValidateObservedChains( + ao plugincommon.AttributedObservation[Observation], +) error { + obs := ao.Observation + observerSupportedChains, err := p.chainSupport.SupportedChains(ao.OracleID) + if err != nil { + return errors.Wrap(err, "failed to get supported chains") + } + + observedChains := append(maps.Keys(obs.FeeComponents), maps.Keys(obs.NativeTokenPrices)...) + observedChains = append(observedChains, maps.Keys(obs.ChainFeeUpdates)...) + for _, chain := range observedChains { + if !observerSupportedChains.Contains(chain) { + return fmt.Errorf("chain %d is not supported by observer", chain) + } + } + + return nil +} From 51465333870e490931296050fe1fdaa69926e1fc Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Tue, 31 Dec 2024 11:54:41 -0500 Subject: [PATCH 03/14] Lint --- commit/chainfee/validate_observation.go | 41 ++++++++++++++++++------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/commit/chainfee/validate_observation.go b/commit/chainfee/validate_observation.go index 8ef23c5c1..ec1768323 100644 --- a/commit/chainfee/validate_observation.go +++ b/commit/chainfee/validate_observation.go @@ -2,9 +2,10 @@ package chainfee import ( "fmt" - "github.com/pkg/errors" "math/big" + "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-ccip/internal/plugincommon" "golang.org/x/exp/maps" @@ -26,14 +27,12 @@ func (p *processor) ValidateObservation( return errors.Wrap(err, "failed to validate observed chains") } - for _, feeComponent := range obs.FeeComponents { - if feeComponent.ExecutionFee == nil || feeComponent.ExecutionFee.Cmp(zero) <= 0 { - return fmt.Errorf("nil or non-positive %s", "execution fee") - } + if err := validateFeeComponents(ao); err != nil { + return errors.Wrap(err, "failed to validate fee components") + } - if feeComponent.DataAvailabilityFee == nil || feeComponent.DataAvailabilityFee.Cmp(zero) < 0 { - return fmt.Errorf("nil or negative %s", "data availability fee") - } + if err := validateChainFeeUpdates(ao); err != nil { + return errors.Wrap(err, "failed to validate chain fee updates") } for _, token := range obs.NativeTokenPrices { @@ -42,16 +41,36 @@ func (p *processor) ValidateObservation( } } - for _, update := range obs.ChainFeeUpdates { - if update.ChainFee.ExecutionFeePriceUSD == nil || update.ChainFee.ExecutionFeePriceUSD.Cmp(zero) <= 0 { + return nil +} + +func validateChainFeeUpdates( + ao plugincommon.AttributedObservation[Observation], +) error { + for _, update := range ao.Observation.ChainFeeUpdates { + if update.ChainFee.ExecutionFeePriceUSD == nil || update.ChainFee.ExecutionFeePriceUSD.Cmp(big.NewInt(0)) <= 0 { return fmt.Errorf("nil or non-positive %s", "execution fee price") } - if update.ChainFee.DataAvFeePriceUSD == nil || update.ChainFee.DataAvFeePriceUSD.Cmp(zero) < 0 { + if update.ChainFee.DataAvFeePriceUSD == nil || update.ChainFee.DataAvFeePriceUSD.Cmp(big.NewInt(0)) < 0 { return fmt.Errorf("nil or negative %s", "data availability fee price") } } + return nil +} +func validateFeeComponents( + ao plugincommon.AttributedObservation[Observation], +) error { + for _, feeComponent := range ao.Observation.FeeComponents { + if feeComponent.ExecutionFee == nil || feeComponent.ExecutionFee.Cmp(big.NewInt(0)) <= 0 { + return fmt.Errorf("nil or non-positive %s", "execution fee") + } + + if feeComponent.DataAvailabilityFee == nil || feeComponent.DataAvailabilityFee.Cmp(big.NewInt(0)) < 0 { + return fmt.Errorf("nil or negative %s", "data availability fee") + } + } return nil } From b36980fe76024240d2867738e81ae45a9e05b3fc Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Tue, 31 Dec 2024 11:56:53 -0500 Subject: [PATCH 04/14] go mod tidy --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index a297202ac..77da41198 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.23.3 require ( github.com/deckarep/golang-set/v2 v2.6.0 github.com/patrickmn/go-cache v2.1.0+incompatible + github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.20.0 github.com/prometheus/client_model v0.6.1 github.com/smartcontractkit/chain-selectors v1.0.34 @@ -38,7 +39,6 @@ require ( github.com/mr-tron/base58 v1.2.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/common v0.59.1 // indirect github.com/prometheus/procfs v0.15.1 // indirect From 22de002e03048eda831c866cbb9005925e0a77b2 Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Mon, 6 Jan 2025 12:44:23 -0500 Subject: [PATCH 05/14] review comments and adding unit test --- commit/chainfee/validate_observation.go | 13 +- commit/chainfee/validate_observation_test.go | 176 +++++++++++++++++++ 2 files changed, 183 insertions(+), 6 deletions(-) create mode 100644 commit/chainfee/validate_observation_test.go diff --git a/commit/chainfee/validate_observation.go b/commit/chainfee/validate_observation.go index ec1768323..31aa25183 100644 --- a/commit/chainfee/validate_observation.go +++ b/commit/chainfee/validate_observation.go @@ -4,8 +4,6 @@ import ( "fmt" "math/big" - "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-ccip/internal/plugincommon" "golang.org/x/exp/maps" @@ -24,15 +22,15 @@ func (p *processor) ValidateObservation( } if err := p.ValidateObservedChains(ao); err != nil { - return errors.Wrap(err, "failed to validate observed chains") + return fmt.Errorf("failed to validate observed chains: %w", err) } if err := validateFeeComponents(ao); err != nil { - return errors.Wrap(err, "failed to validate fee components") + return fmt.Errorf("failed to validate fee components: %w", err) } if err := validateChainFeeUpdates(ao); err != nil { - return errors.Wrap(err, "failed to validate chain fee updates") + return fmt.Errorf("failed to validate chain fee updates: %w", err) } for _, token := range obs.NativeTokenPrices { @@ -55,6 +53,9 @@ func validateChainFeeUpdates( if update.ChainFee.DataAvFeePriceUSD == nil || update.ChainFee.DataAvFeePriceUSD.Cmp(big.NewInt(0)) < 0 { return fmt.Errorf("nil or negative %s", "data availability fee price") } + if update.Timestamp.IsZero() { + return fmt.Errorf("zero timestamp") + } } return nil } @@ -80,7 +81,7 @@ func (p *processor) ValidateObservedChains( obs := ao.Observation observerSupportedChains, err := p.chainSupport.SupportedChains(ao.OracleID) if err != nil { - return errors.Wrap(err, "failed to get supported chains") + return fmt.Errorf("failed to get supported chains: %w", err) } observedChains := append(maps.Keys(obs.FeeComponents), maps.Keys(obs.NativeTokenPrices)...) diff --git a/commit/chainfee/validate_observation_test.go b/commit/chainfee/validate_observation_test.go new file mode 100644 index 000000000..8c48a73ee --- /dev/null +++ b/commit/chainfee/validate_observation_test.go @@ -0,0 +1,176 @@ +package chainfee + +import ( + "github.com/stretchr/testify/require" + "math/big" + "testing" + "time" + + "github.com/smartcontractkit/chainlink-ccip/internal/plugincommon" + "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +func Test_validateFeeComponentsAndChainFeeUpdates(t *testing.T) { + fourHoursAgo := time.Now().Add(-4 * time.Hour).UTC().Truncate(time.Hour) + tests := []struct { + name string + feeComponents map[ccipocr3.ChainSelector]types.ChainFeeComponents + chainFeeUpdates map[ccipocr3.ChainSelector]Update + expectedFeeComponentError string + expectedChainFeeUpdatesError string + }{ + { + name: "valid fee components", + feeComponents: map[ccipocr3.ChainSelector]types.ChainFeeComponents{ + 1: { + ExecutionFee: big.NewInt(10), + DataAvailabilityFee: big.NewInt(20), + }, + }, + expectedFeeComponentError: "", + }, + { + name: "nil execution fee", + feeComponents: map[ccipocr3.ChainSelector]types.ChainFeeComponents{ + 1: { + ExecutionFee: nil, + DataAvailabilityFee: big.NewInt(20), + }, + }, + expectedFeeComponentError: "nil or non-positive execution fee", + }, + { + name: "non-positive execution fee", + feeComponents: map[ccipocr3.ChainSelector]types.ChainFeeComponents{ + 1: { + ExecutionFee: big.NewInt(0), + DataAvailabilityFee: big.NewInt(20), + }, + }, + expectedFeeComponentError: "nil or non-positive execution fee", + }, + { + name: "nil data availability fee", + feeComponents: map[ccipocr3.ChainSelector]types.ChainFeeComponents{ + 1: { + ExecutionFee: big.NewInt(10), + DataAvailabilityFee: nil, + }, + }, + expectedFeeComponentError: "nil or negative data availability fee", + }, + { + name: "negative data availability fee", + feeComponents: map[ccipocr3.ChainSelector]types.ChainFeeComponents{ + 1: { + ExecutionFee: big.NewInt(10), + DataAvailabilityFee: big.NewInt(-1), + }, + }, + expectedFeeComponentError: "nil or negative data availability fee", + }, + { + name: "valid chain fee updates", + chainFeeUpdates: map[ccipocr3.ChainSelector]Update{ + 1: { + ChainFee: ComponentsUSDPrices{ + ExecutionFeePriceUSD: big.NewInt(10), + DataAvFeePriceUSD: big.NewInt(20), + }, + Timestamp: fourHoursAgo, + }, + }, + expectedChainFeeUpdatesError: "", + }, + { + name: "nil execution fee price - chain fee updates", + chainFeeUpdates: map[ccipocr3.ChainSelector]Update{ + 1: { + ChainFee: ComponentsUSDPrices{ + ExecutionFeePriceUSD: nil, + DataAvFeePriceUSD: big.NewInt(20), + }, + Timestamp: fourHoursAgo, + }, + }, + expectedChainFeeUpdatesError: "nil or non-positive execution fee price", + }, + { + name: "non-positive execution fee price - chain fee updates", + chainFeeUpdates: map[ccipocr3.ChainSelector]Update{ + 1: { + ChainFee: ComponentsUSDPrices{ + ExecutionFeePriceUSD: big.NewInt(0), + DataAvFeePriceUSD: big.NewInt(20), + }, + Timestamp: fourHoursAgo, + }, + }, + expectedChainFeeUpdatesError: "nil or non-positive execution fee price", + }, + { + name: "nil data availability fee price - chain fee updates", + chainFeeUpdates: map[ccipocr3.ChainSelector]Update{ + 1: { + ChainFee: ComponentsUSDPrices{ + ExecutionFeePriceUSD: big.NewInt(10), + DataAvFeePriceUSD: nil, + }, + Timestamp: fourHoursAgo, + }, + }, + expectedChainFeeUpdatesError: "nil or negative data availability fee price", + }, + { + name: "negative data availability fee price - chain fee updates", + chainFeeUpdates: map[ccipocr3.ChainSelector]Update{ + 1: { + ChainFee: ComponentsUSDPrices{ + ExecutionFeePriceUSD: big.NewInt(10), + DataAvFeePriceUSD: big.NewInt(-1), + }, + Timestamp: fourHoursAgo, + }, + }, + expectedChainFeeUpdatesError: "nil or negative data availability fee price", + }, + { + name: "zero timestamp - chain fee updates", + chainFeeUpdates: map[ccipocr3.ChainSelector]Update{ + 1: { + ChainFee: ComponentsUSDPrices{ + ExecutionFeePriceUSD: big.NewInt(10), + DataAvFeePriceUSD: big.NewInt(20), + }, + }, + }, + expectedChainFeeUpdatesError: "zero timestamp", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ao := plugincommon.AttributedObservation[Observation]{ + Observation: Observation{ + FeeComponents: tt.feeComponents, + ChainFeeUpdates: tt.chainFeeUpdates, + }, + } + err := validateFeeComponents(ao) + if tt.expectedFeeComponentError == "" { + require.NoError(t, err) + } else { + require.Error(t, err) + require.Contains(t, err.Error(), tt.expectedFeeComponentError) + } + err = validateChainFeeUpdates(ao) + if tt.expectedChainFeeUpdatesError == "" { + require.NoError(t, err) + } else { + require.Error(t, err) + require.Contains(t, err.Error(), tt.expectedChainFeeUpdatesError) + } + }) + } +} From eaf6b018ac65e0dcfedb58f6c696d655e30b61eb Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Mon, 6 Jan 2025 13:19:11 -0500 Subject: [PATCH 06/14] Lint fix --- commit/chainfee/validate_observation_test.go | 3 ++- go.mod | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/commit/chainfee/validate_observation_test.go b/commit/chainfee/validate_observation_test.go index 8c48a73ee..7ac053c57 100644 --- a/commit/chainfee/validate_observation_test.go +++ b/commit/chainfee/validate_observation_test.go @@ -1,11 +1,12 @@ package chainfee import ( - "github.com/stretchr/testify/require" "math/big" "testing" "time" + "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-ccip/internal/plugincommon" "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" "github.com/smartcontractkit/chainlink-common/pkg/types" diff --git a/go.mod b/go.mod index 77da41198..a297202ac 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.23.3 require ( github.com/deckarep/golang-set/v2 v2.6.0 github.com/patrickmn/go-cache v2.1.0+incompatible - github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.20.0 github.com/prometheus/client_model v0.6.1 github.com/smartcontractkit/chain-selectors v1.0.34 @@ -39,6 +38,7 @@ require ( github.com/mr-tron/base58 v1.2.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/common v0.59.1 // indirect github.com/prometheus/procfs v0.15.1 // indirect From adf719ddc198302878cb7316566813610a6b8421 Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Mon, 6 Jan 2025 14:22:01 -0500 Subject: [PATCH 07/14] goimports with local --- commit/chainfee/validate_observation_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/commit/chainfee/validate_observation_test.go b/commit/chainfee/validate_observation_test.go index 7ac053c57..b0755c2ba 100644 --- a/commit/chainfee/validate_observation_test.go +++ b/commit/chainfee/validate_observation_test.go @@ -7,9 +7,10 @@ import ( "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-ccip/internal/plugincommon" "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" - "github.com/smartcontractkit/chainlink-common/pkg/types" ) func Test_validateFeeComponentsAndChainFeeUpdates(t *testing.T) { From 941d02960fbdb5b6579ab129b00267b7d2271a81 Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Wed, 8 Jan 2025 11:16:21 -0500 Subject: [PATCH 08/14] adding additional checks per review --- commit/chainfee/validate_observation.go | 39 ++++- commit/chainfee/validate_observation_test.go | 144 ++++++++++++++++++- 2 files changed, 175 insertions(+), 8 deletions(-) diff --git a/commit/chainfee/validate_observation.go b/commit/chainfee/validate_observation.go index 31aa25183..ec9713a21 100644 --- a/commit/chainfee/validate_observation.go +++ b/commit/chainfee/validate_observation.go @@ -3,8 +3,12 @@ package chainfee import ( "fmt" "math/big" + "time" + + mapset "github.com/deckarep/golang-set/v2" "github.com/smartcontractkit/chainlink-ccip/internal/plugincommon" + "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" "golang.org/x/exp/maps" ) @@ -20,8 +24,11 @@ func (p *processor) ValidateObservation( if err := plugincommon.ValidateFChain(obs.FChain); err != nil { return fmt.Errorf("failed to validate FChain: %w", err) } - - if err := p.ValidateObservedChains(ao); err != nil { + observerSupportedChains, err := p.chainSupport.SupportedChains(ao.OracleID) + if err != nil { + return fmt.Errorf("failed to get supported chains: %w", err) + } + if err := validateObservedChains(ao, observerSupportedChains); err != nil { return fmt.Errorf("failed to validate observed chains: %w", err) } @@ -39,6 +46,9 @@ func (p *processor) ValidateObservation( } } + if obs.TimestampNow.IsZero() || obs.TimestampNow.After(time.Now().UTC()) { + return fmt.Errorf("invalid timestamp now value %s", obs.TimestampNow.String()) + } return nil } @@ -75,13 +85,16 @@ func validateFeeComponents( return nil } -func (p *processor) ValidateObservedChains( +func validateObservedChains( ao plugincommon.AttributedObservation[Observation], + observerSupportedChains mapset.Set[ccipocr3.ChainSelector], ) error { obs := ao.Observation - observerSupportedChains, err := p.chainSupport.SupportedChains(ao.OracleID) - if err != nil { - return fmt.Errorf("failed to get supported chains: %w", err) + if !areMapKeysEqual(obs.FeeComponents, obs.NativeTokenPrices) { + return fmt.Errorf("fee components and native token prices have different observed chains") + } + if !areMapKeysEqual(obs.NativeTokenPrices, obs.ChainFeeUpdates) { + return fmt.Errorf("native token and chain fee updates prices have different observed chains") } observedChains := append(maps.Keys(obs.FeeComponents), maps.Keys(obs.NativeTokenPrices)...) @@ -94,3 +107,17 @@ func (p *processor) ValidateObservedChains( return nil } + +func areMapKeysEqual[T, T1 comparable](map1 map[ccipocr3.ChainSelector]T, map2 map[ccipocr3.ChainSelector]T1) bool { + if len(map1) != len(map2) { + return false // Maps have different number of keys + } + + for key := range map1 { + if _, exists := map2[key]; !exists { + return false // Key in map1 doesn't exist in map2 + } + } + + return true // All keys in map1 exist in map2 +} diff --git a/commit/chainfee/validate_observation_test.go b/commit/chainfee/validate_observation_test.go index b0755c2ba..121bf3851 100644 --- a/commit/chainfee/validate_observation_test.go +++ b/commit/chainfee/validate_observation_test.go @@ -5,12 +5,13 @@ import ( "testing" "time" - "github.com/stretchr/testify/require" + mapset "github.com/deckarep/golang-set/v2" - "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-ccip/internal/plugincommon" "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink-common/pkg/types" ) func Test_validateFeeComponentsAndChainFeeUpdates(t *testing.T) { @@ -176,3 +177,142 @@ func Test_validateFeeComponentsAndChainFeeUpdates(t *testing.T) { }) } } + +func Test_validateObservedChains(t *testing.T) { + fourHoursAgo := time.Now().Add(-4 * time.Hour).UTC().Truncate(time.Hour) + tests := []struct { + name string + ao plugincommon.AttributedObservation[Observation] + observerSupportedChains mapset.Set[ccipocr3.ChainSelector] + expectedError string + }{ + { + name: "valid observed chains", + ao: plugincommon.AttributedObservation[Observation]{ + Observation: Observation{ + FeeComponents: map[ccipocr3.ChainSelector]types.ChainFeeComponents{ + 1: { + ExecutionFee: big.NewInt(10), + DataAvailabilityFee: big.NewInt(20), + }, + }, + NativeTokenPrices: map[ccipocr3.ChainSelector]ccipocr3.BigInt{ + 1: { + Int: big.NewInt(100), + }, + }, + ChainFeeUpdates: map[ccipocr3.ChainSelector]Update{ + 1: { + ChainFee: ComponentsUSDPrices{ + ExecutionFeePriceUSD: big.NewInt(10), + DataAvFeePriceUSD: big.NewInt(20), + }, + Timestamp: fourHoursAgo, + }, + }, + }, + }, + observerSupportedChains: mapset.NewSet[ccipocr3.ChainSelector](1), + expectedError: "", + }, + { + name: "unsupported chain", + ao: plugincommon.AttributedObservation[Observation]{ + Observation: Observation{ + FeeComponents: map[ccipocr3.ChainSelector]types.ChainFeeComponents{ + 1: { + ExecutionFee: big.NewInt(10), + DataAvailabilityFee: big.NewInt(20), + }, + }, + NativeTokenPrices: map[ccipocr3.ChainSelector]ccipocr3.BigInt{ + 1: { + Int: big.NewInt(100), + }, + }, + ChainFeeUpdates: map[ccipocr3.ChainSelector]Update{ + 1: { + ChainFee: ComponentsUSDPrices{ + ExecutionFeePriceUSD: big.NewInt(10), + DataAvFeePriceUSD: big.NewInt(20), + }, + Timestamp: fourHoursAgo, + }, + }, + }, + }, + observerSupportedChains: mapset.NewSet[ccipocr3.ChainSelector](2), + expectedError: "chain 1 is not supported by observer", + }, + { + name: "different observed chains in fee components and native token prices", + ao: plugincommon.AttributedObservation[Observation]{ + Observation: Observation{ + FeeComponents: map[ccipocr3.ChainSelector]types.ChainFeeComponents{ + 1: { + ExecutionFee: big.NewInt(10), + DataAvailabilityFee: big.NewInt(20), + }, + }, + NativeTokenPrices: map[ccipocr3.ChainSelector]ccipocr3.BigInt{ + 2: { + Int: big.NewInt(100), + }, + }, + ChainFeeUpdates: map[ccipocr3.ChainSelector]Update{ + 1: { + ChainFee: ComponentsUSDPrices{ + ExecutionFeePriceUSD: big.NewInt(10), + DataAvFeePriceUSD: big.NewInt(20), + }, + Timestamp: fourHoursAgo, + }, + }, + }, + }, + observerSupportedChains: mapset.NewSet[ccipocr3.ChainSelector](1, 2), + expectedError: "fee components and native token prices have different observed chains", + }, + { + name: "different observed chains in native token prices and chain fee updates", + ao: plugincommon.AttributedObservation[Observation]{ + Observation: Observation{ + FeeComponents: map[ccipocr3.ChainSelector]types.ChainFeeComponents{ + 1: { + ExecutionFee: big.NewInt(10), + DataAvailabilityFee: big.NewInt(20), + }, + }, + NativeTokenPrices: map[ccipocr3.ChainSelector]ccipocr3.BigInt{ + 1: { + Int: big.NewInt(100), + }, + }, + ChainFeeUpdates: map[ccipocr3.ChainSelector]Update{ + 2: { + ChainFee: ComponentsUSDPrices{ + ExecutionFeePriceUSD: big.NewInt(10), + DataAvFeePriceUSD: big.NewInt(20), + }, + Timestamp: fourHoursAgo, + }, + }, + }, + }, + observerSupportedChains: mapset.NewSet[ccipocr3.ChainSelector](1, 2, 3), + expectedError: "native token and chain fee updates prices have different observed chains", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := validateObservedChains(tt.ao, tt.observerSupportedChains) + if tt.expectedError == "" { + require.NoError(t, err) + } else { + require.Error(t, err) + require.Contains(t, err.Error(), tt.expectedError) + } + }) + } +} From a0ac3ea010b76037d78f4d20e39cada2fd152f5c Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Wed, 8 Jan 2025 11:27:44 -0500 Subject: [PATCH 09/14] Lint fix --- commit/chainfee/validate_observation_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/commit/chainfee/validate_observation_test.go b/commit/chainfee/validate_observation_test.go index 121bf3851..697cd262d 100644 --- a/commit/chainfee/validate_observation_test.go +++ b/commit/chainfee/validate_observation_test.go @@ -9,9 +9,10 @@ import ( "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-ccip/internal/plugincommon" "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" - "github.com/smartcontractkit/chainlink-common/pkg/types" ) func Test_validateFeeComponentsAndChainFeeUpdates(t *testing.T) { From 9cb84c1d8c2f4fae8dccc9d17c6feb5045d01ef9 Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Wed, 8 Jan 2025 19:40:54 -0500 Subject: [PATCH 10/14] Trigger workflow with dummy commit From 960a2e848c0165ce7c58265a957a44bf4177735d Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Thu, 9 Jan 2025 15:35:16 -0500 Subject: [PATCH 11/14] Add filter by intersecting unique chains --- commit/chainfee/observation.go | 32 +++- commit/chainfee/observation_test.go | 189 +++++++++++++++++++++++- commit/chainfee/validate_observation.go | 6 +- 3 files changed, 218 insertions(+), 9 deletions(-) diff --git a/commit/chainfee/observation.go b/commit/chainfee/observation.go index a0e0df29e..2174ff8db 100644 --- a/commit/chainfee/observation.go +++ b/commit/chainfee/observation.go @@ -7,9 +7,13 @@ import ( "sort" "time" - "github.com/smartcontractkit/chainlink-common/pkg/types" + mapset "github.com/deckarep/golang-set/v2" + "golang.org/x/exp/maps" + "golang.org/x/sync/errgroup" + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-ccip/internal/plugintypes" cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" ) @@ -85,11 +89,20 @@ func (p *processor) Observation( "timestampNow", now, ) + uniqueChains := mapset.NewSet[cciptypes.ChainSelector](maps.Keys(feeComponents)...) + uniqueChains = uniqueChains.Intersect(mapset.NewSet(maps.Keys(nativeTokenPrices)...)) + uniqueChains = uniqueChains.Intersect(mapset.NewSet(maps.Keys(chainFeeUpdates)...)) + + if len(uniqueChains.ToSlice()) == 0 { + p.lggr.Info("observations don't have any unique chains") + return Observation{}, nil + } + obs := Observation{ FChain: fChain, - FeeComponents: feeComponents, - NativeTokenPrices: nativeTokenPrices, - ChainFeeUpdates: chainFeeUpdates, + FeeComponents: filterMapByUniqueChains(feeComponents, uniqueChains), + NativeTokenPrices: filterMapByUniqueChains(nativeTokenPrices, uniqueChains), + ChainFeeUpdates: filterMapByUniqueChains(chainFeeUpdates, uniqueChains), TimestampNow: now, } @@ -97,6 +110,17 @@ func (p *processor) Observation( return obs, nil } +// filterMapBySet filters a map based on the keys present in the set. +func filterMapByUniqueChains[T comparable](m map[cciptypes.ChainSelector]T, s mapset.Set[cciptypes.ChainSelector]) map[cciptypes.ChainSelector]T { + filtered := make(map[cciptypes.ChainSelector]T) + for k, v := range m { + if s.Contains(k) { + filtered[k] = v + } + } + return filtered +} + func (p *processor) observeFChain() map[cciptypes.ChainSelector]int { fChain, err := p.homeChain.GetFChain() if err != nil { diff --git a/commit/chainfee/observation_test.go b/commit/chainfee/observation_test.go index 8fa3bf4c8..47b4ddf2f 100644 --- a/commit/chainfee/observation_test.go +++ b/commit/chainfee/observation_test.go @@ -10,11 +10,12 @@ import ( "golang.org/x/exp/maps" mapset "github.com/deckarep/golang-set/v2" + "github.com/smartcontractkit/libocr/commontypes" + "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" - "github.com/smartcontractkit/libocr/commontypes" - "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-ccip/internal/plugintypes" "github.com/smartcontractkit/chainlink-ccip/mocks/internal_/plugincommon" @@ -169,3 +170,187 @@ func Test_processor_Observation(t *testing.T) { }) } } + +func Test_unique_chain_filter_in_Observation(t *testing.T) { + fourHoursAgo := time.Now().Add(-4 * time.Hour).UTC().Truncate(time.Hour) + + testCases := []struct { + name string + supportedChains []ccipocr3.ChainSelector + chainFeeComponents map[ccipocr3.ChainSelector]types.ChainFeeComponents + nativeTokenPrices map[ccipocr3.ChainSelector]ccipocr3.BigInt + existingChainFeePriceUpdates map[ccipocr3.ChainSelector]plugintypes.TimestampedBig + fChain map[ccipocr3.ChainSelector]int + dstChain ccipocr3.ChainSelector + expUniqueChains int + }{ + { + name: "unique chains intersection", + supportedChains: []ccipocr3.ChainSelector{1, 2, 3}, + dstChain: 3, + chainFeeComponents: map[ccipocr3.ChainSelector]types.ChainFeeComponents{ + 1: { + ExecutionFee: big.NewInt(10), + DataAvailabilityFee: big.NewInt(20), + }, + 2: { + ExecutionFee: big.NewInt(100), + DataAvailabilityFee: big.NewInt(200), + }, + }, + nativeTokenPrices: map[ccipocr3.ChainSelector]ccipocr3.BigInt{ + 1: ccipocr3.NewBigIntFromInt64(1000), + 2: ccipocr3.NewBigIntFromInt64(2000), + }, + existingChainFeePriceUpdates: map[ccipocr3.ChainSelector]plugintypes.TimestampedBig{ + 1: { + Timestamp: fourHoursAgo, + Value: ccipocr3.NewBigInt(FeeComponentsToPackedFee(ComponentsUSDPrices{ + ExecutionFeePriceUSD: big.NewInt(1234), + DataAvFeePriceUSD: big.NewInt(4321), + })), + }, + 2: { + Timestamp: fourHoursAgo, + Value: ccipocr3.NewBigInt(FeeComponentsToPackedFee(ComponentsUSDPrices{ + ExecutionFeePriceUSD: big.NewInt(12340), + DataAvFeePriceUSD: big.NewInt(43210), + })), + }, + }, + fChain: map[ccipocr3.ChainSelector]int{ + 1: 1, + 2: 2, + 3: 1, + }, + expUniqueChains: 2, + }, + { + name: "only one unique chains", + supportedChains: []ccipocr3.ChainSelector{1, 2, 3}, + dstChain: 3, + chainFeeComponents: map[ccipocr3.ChainSelector]types.ChainFeeComponents{ + 1: { + ExecutionFee: big.NewInt(10), + DataAvailabilityFee: big.NewInt(20), + }, + 2: { + ExecutionFee: big.NewInt(100), + DataAvailabilityFee: big.NewInt(200), + }, + }, + nativeTokenPrices: map[ccipocr3.ChainSelector]ccipocr3.BigInt{ + 1: ccipocr3.NewBigIntFromInt64(1000), + }, + existingChainFeePriceUpdates: map[ccipocr3.ChainSelector]plugintypes.TimestampedBig{ + 1: { + Timestamp: fourHoursAgo, + Value: ccipocr3.NewBigInt(FeeComponentsToPackedFee(ComponentsUSDPrices{ + ExecutionFeePriceUSD: big.NewInt(1234), + DataAvFeePriceUSD: big.NewInt(4321), + })), + }, + 3: { + Timestamp: fourHoursAgo, + Value: ccipocr3.NewBigInt(FeeComponentsToPackedFee(ComponentsUSDPrices{ + ExecutionFeePriceUSD: big.NewInt(1234), + DataAvFeePriceUSD: big.NewInt(4321), + })), + }, + }, + fChain: map[ccipocr3.ChainSelector]int{ + 1: 1, + 2: 2, + 3: 1, + }, + expUniqueChains: 1, + }, + { + name: "zero unique chains", + supportedChains: []ccipocr3.ChainSelector{1, 2, 3}, + dstChain: 3, + chainFeeComponents: map[ccipocr3.ChainSelector]types.ChainFeeComponents{ + 1: { + ExecutionFee: big.NewInt(10), + DataAvailabilityFee: big.NewInt(20), + }, + 2: { + ExecutionFee: big.NewInt(100), + DataAvailabilityFee: big.NewInt(200), + }, + }, + nativeTokenPrices: map[ccipocr3.ChainSelector]ccipocr3.BigInt{ + 1: ccipocr3.NewBigIntFromInt64(1000), + }, + existingChainFeePriceUpdates: map[ccipocr3.ChainSelector]plugintypes.TimestampedBig{ + 3: { + Timestamp: fourHoursAgo, + Value: ccipocr3.NewBigInt(FeeComponentsToPackedFee(ComponentsUSDPrices{ + ExecutionFeePriceUSD: big.NewInt(1234), + DataAvFeePriceUSD: big.NewInt(4321), + })), + }, + }, + fChain: map[ccipocr3.ChainSelector]int{ + 1: 1, + 2: 2, + 3: 1, + }, + expUniqueChains: 0, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + cs := plugincommon.NewMockChainSupport(t) + ccipReader := reader.NewMockCCIPReader(t) + homeChain := reader2.NewMockHomeChain(t) + oracleID := commontypes.OracleID(rand.Int() % 255) + lggr := logger.Test(t) + ctx := tests.Context(t) + + p := &processor{ + lggr: lggr, + chainSupport: cs, + destChain: tc.dstChain, + ccipReader: ccipReader, + oracleID: oracleID, + homeChain: homeChain, + metricsReporter: NoopMetrics{}, + } + + supportedSet := mapset.NewSet(tc.supportedChains...) + cs.EXPECT().DestChain().Return(tc.dstChain).Maybe() + cs.EXPECT().SupportedChains(oracleID). + Return(supportedSet, nil).Maybe() + + supportedSet.Remove(tc.dstChain) + slicesWithoutDst := supportedSet.ToSlice() + sort.Slice(slicesWithoutDst, func(i, j int) bool { return slicesWithoutDst[i] < slicesWithoutDst[j] }) + + ccipReader.EXPECT().GetChainsFeeComponents(ctx, slicesWithoutDst). + Return(tc.chainFeeComponents).Maybe() + + ccipReader.EXPECT().GetWrappedNativeTokenPriceUSD(ctx, slicesWithoutDst). + Return(tc.nativeTokenPrices).Maybe() + + ccipReader.EXPECT().GetChainFeePriceUpdate(ctx, slicesWithoutDst). + Return(tc.existingChainFeePriceUpdates).Maybe() + + homeChain.EXPECT().GetFChain().Return(tc.fChain, nil).Maybe() + + obs, err := p.Observation(ctx, Outcome{}, Query{}) + require.NoError(t, err) + if tc.expUniqueChains == 0 { + require.Empty(t, obs) + return + } + + require.True(t, tc.expUniqueChains == len(maps.Keys(obs.FeeComponents))) + require.True(t, tc.expUniqueChains == len(maps.Keys(obs.NativeTokenPrices))) + require.True(t, tc.expUniqueChains == len(maps.Keys(obs.ChainFeeUpdates))) + require.ElementsMatch(t, maps.Keys(obs.FeeComponents), maps.Keys(obs.NativeTokenPrices)) + require.ElementsMatch(t, maps.Keys(obs.NativeTokenPrices), maps.Keys(obs.ChainFeeUpdates)) + }) + } +} diff --git a/commit/chainfee/validate_observation.go b/commit/chainfee/validate_observation.go index ec9713a21..d241ad8e7 100644 --- a/commit/chainfee/validate_observation.go +++ b/commit/chainfee/validate_observation.go @@ -110,14 +110,14 @@ func validateObservedChains( func areMapKeysEqual[T, T1 comparable](map1 map[ccipocr3.ChainSelector]T, map2 map[ccipocr3.ChainSelector]T1) bool { if len(map1) != len(map2) { - return false // Maps have different number of keys + return false } for key := range map1 { if _, exists := map2[key]; !exists { - return false // Key in map1 doesn't exist in map2 + return false } } - return true // All keys in map1 exist in map2 + return true } From a3acd67335e7bf6424386ddc586cb6cc20f0beb7 Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Thu, 9 Jan 2025 22:06:36 -0500 Subject: [PATCH 12/14] lint --- commit/chainfee/observation.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/commit/chainfee/observation.go b/commit/chainfee/observation.go index 2174ff8db..34a8864ff 100644 --- a/commit/chainfee/observation.go +++ b/commit/chainfee/observation.go @@ -111,7 +111,10 @@ func (p *processor) Observation( } // filterMapBySet filters a map based on the keys present in the set. -func filterMapByUniqueChains[T comparable](m map[cciptypes.ChainSelector]T, s mapset.Set[cciptypes.ChainSelector]) map[cciptypes.ChainSelector]T { +func filterMapByUniqueChains[T comparable]( + m map[cciptypes.ChainSelector]T, + s mapset.Set[cciptypes.ChainSelector], +) map[cciptypes.ChainSelector]T { filtered := make(map[cciptypes.ChainSelector]T) for k, v := range m { if s.Contains(k) { From deac5db24875daba7389a9582957c7d4cc7f5838 Mon Sep 17 00:00:00 2001 From: asoliman Date: Mon, 13 Jan 2025 14:14:12 +0400 Subject: [PATCH 13/14] Fix chain fee validation. ChainFeeUpdates is irrelevant for key checks, FeeQuoter can have some tokens and not others at any time (especially at the beginning) --- commit/chainfee/observation.go | 3 +- commit/chainfee/observation_test.go | 8 ++---- commit/chainfee/outcome.go | 12 ++++++-- commit/chainfee/types.go | 4 +++ commit/chainfee/validate_observation.go | 7 +++-- commit/chainfee/validate_observation_test.go | 29 -------------------- 6 files changed, 22 insertions(+), 41 deletions(-) diff --git a/commit/chainfee/observation.go b/commit/chainfee/observation.go index 34a8864ff..1c146e578 100644 --- a/commit/chainfee/observation.go +++ b/commit/chainfee/observation.go @@ -91,7 +91,6 @@ func (p *processor) Observation( uniqueChains := mapset.NewSet[cciptypes.ChainSelector](maps.Keys(feeComponents)...) uniqueChains = uniqueChains.Intersect(mapset.NewSet(maps.Keys(nativeTokenPrices)...)) - uniqueChains = uniqueChains.Intersect(mapset.NewSet(maps.Keys(chainFeeUpdates)...)) if len(uniqueChains.ToSlice()) == 0 { p.lggr.Info("observations don't have any unique chains") @@ -102,7 +101,7 @@ func (p *processor) Observation( FChain: fChain, FeeComponents: filterMapByUniqueChains(feeComponents, uniqueChains), NativeTokenPrices: filterMapByUniqueChains(nativeTokenPrices, uniqueChains), - ChainFeeUpdates: filterMapByUniqueChains(chainFeeUpdates, uniqueChains), + ChainFeeUpdates: chainFeeUpdates, TimestampNow: now, } diff --git a/commit/chainfee/observation_test.go b/commit/chainfee/observation_test.go index 47b4ddf2f..3ebbf2815 100644 --- a/commit/chainfee/observation_test.go +++ b/commit/chainfee/observation_test.go @@ -226,7 +226,7 @@ func Test_unique_chain_filter_in_Observation(t *testing.T) { expUniqueChains: 2, }, { - name: "only one unique chains", + name: "only one unique chain between fee components and native token prices", supportedChains: []ccipocr3.ChainSelector{1, 2, 3}, dstChain: 3, chainFeeComponents: map[ccipocr3.ChainSelector]types.ChainFeeComponents{ @@ -266,7 +266,7 @@ func Test_unique_chain_filter_in_Observation(t *testing.T) { expUniqueChains: 1, }, { - name: "zero unique chains", + name: "zero unique chains between fee components and native token prices", supportedChains: []ccipocr3.ChainSelector{1, 2, 3}, dstChain: 3, chainFeeComponents: map[ccipocr3.ChainSelector]types.ChainFeeComponents{ @@ -280,7 +280,7 @@ func Test_unique_chain_filter_in_Observation(t *testing.T) { }, }, nativeTokenPrices: map[ccipocr3.ChainSelector]ccipocr3.BigInt{ - 1: ccipocr3.NewBigIntFromInt64(1000), + 3: ccipocr3.NewBigIntFromInt64(1000), }, existingChainFeePriceUpdates: map[ccipocr3.ChainSelector]plugintypes.TimestampedBig{ 3: { @@ -348,9 +348,7 @@ func Test_unique_chain_filter_in_Observation(t *testing.T) { require.True(t, tc.expUniqueChains == len(maps.Keys(obs.FeeComponents))) require.True(t, tc.expUniqueChains == len(maps.Keys(obs.NativeTokenPrices))) - require.True(t, tc.expUniqueChains == len(maps.Keys(obs.ChainFeeUpdates))) require.ElementsMatch(t, maps.Keys(obs.FeeComponents), maps.Keys(obs.NativeTokenPrices)) - require.ElementsMatch(t, maps.Keys(obs.NativeTokenPrices), maps.Keys(obs.ChainFeeUpdates)) }) } } diff --git a/commit/chainfee/outcome.go b/commit/chainfee/outcome.go index a08c0124c..30bb7dd27 100644 --- a/commit/chainfee/outcome.go +++ b/commit/chainfee/outcome.go @@ -216,9 +216,17 @@ func (p *processor) getGasPricesToUpdate( for chain, currentChainFee := range currentChainUSDFees { packedFee := cciptypes.NewBigInt(FeeComponentsToPackedFee(currentChainFee)) lastUpdate, exists := latestUpdates[chain] - nextUpdateTime := lastUpdate.Timestamp.Add(p.cfg.RemoteGasPriceBatchWriteFrequency.Duration()) // If the chain is not in the fee quoter updates or is stale, then we should update it - if !exists || obsTimestamp.After(nextUpdateTime) { + if !exists { + gasPrices = append(gasPrices, cciptypes.GasPriceChain{ + ChainSel: chain, + GasPrice: packedFee, + }) + continue + } + + nextUpdateTime := lastUpdate.Timestamp.Add(p.cfg.RemoteGasPriceBatchWriteFrequency.Duration()) + if obsTimestamp.After(nextUpdateTime) { gasPrices = append(gasPrices, cciptypes.GasPriceChain{ ChainSel: chain, GasPrice: packedFee, diff --git a/commit/chainfee/types.go b/commit/chainfee/types.go index 91ffef1b8..6082af961 100644 --- a/commit/chainfee/types.go +++ b/commit/chainfee/types.go @@ -58,3 +58,7 @@ type NoopMetrics struct{} func (n NoopMetrics) TrackChainFeeObservation(Observation) {} func (n NoopMetrics) TrackChainFeeOutcome(Outcome) {} + +func (o Observation) IsEmpty() bool { + return len(o.FeeComponents) == 0 && len(o.NativeTokenPrices) == 0 && len(o.ChainFeeUpdates) == 0 && len(o.FChain) == 0 && o.TimestampNow.IsZero() +} diff --git a/commit/chainfee/validate_observation.go b/commit/chainfee/validate_observation.go index d241ad8e7..a2bc5a393 100644 --- a/commit/chainfee/validate_observation.go +++ b/commit/chainfee/validate_observation.go @@ -21,6 +21,10 @@ func (p *processor) ValidateObservation( obs := ao.Observation zero := big.NewInt(0) + if obs.IsEmpty() { + return nil + } + if err := plugincommon.ValidateFChain(obs.FChain); err != nil { return fmt.Errorf("failed to validate FChain: %w", err) } @@ -93,9 +97,6 @@ func validateObservedChains( if !areMapKeysEqual(obs.FeeComponents, obs.NativeTokenPrices) { return fmt.Errorf("fee components and native token prices have different observed chains") } - if !areMapKeysEqual(obs.NativeTokenPrices, obs.ChainFeeUpdates) { - return fmt.Errorf("native token and chain fee updates prices have different observed chains") - } observedChains := append(maps.Keys(obs.FeeComponents), maps.Keys(obs.NativeTokenPrices)...) observedChains = append(observedChains, maps.Keys(obs.ChainFeeUpdates)...) diff --git a/commit/chainfee/validate_observation_test.go b/commit/chainfee/validate_observation_test.go index 697cd262d..65ef1bd3a 100644 --- a/commit/chainfee/validate_observation_test.go +++ b/commit/chainfee/validate_observation_test.go @@ -274,35 +274,6 @@ func Test_validateObservedChains(t *testing.T) { observerSupportedChains: mapset.NewSet[ccipocr3.ChainSelector](1, 2), expectedError: "fee components and native token prices have different observed chains", }, - { - name: "different observed chains in native token prices and chain fee updates", - ao: plugincommon.AttributedObservation[Observation]{ - Observation: Observation{ - FeeComponents: map[ccipocr3.ChainSelector]types.ChainFeeComponents{ - 1: { - ExecutionFee: big.NewInt(10), - DataAvailabilityFee: big.NewInt(20), - }, - }, - NativeTokenPrices: map[ccipocr3.ChainSelector]ccipocr3.BigInt{ - 1: { - Int: big.NewInt(100), - }, - }, - ChainFeeUpdates: map[ccipocr3.ChainSelector]Update{ - 2: { - ChainFee: ComponentsUSDPrices{ - ExecutionFeePriceUSD: big.NewInt(10), - DataAvFeePriceUSD: big.NewInt(20), - }, - Timestamp: fourHoursAgo, - }, - }, - }, - }, - observerSupportedChains: mapset.NewSet[ccipocr3.ChainSelector](1, 2, 3), - expectedError: "native token and chain fee updates prices have different observed chains", - }, } for _, tt := range tests { From cb2ed66b5aa8ece2ce8a8b21c9174e591bbd7e72 Mon Sep 17 00:00:00 2001 From: asoliman Date: Mon, 13 Jan 2025 14:32:15 +0400 Subject: [PATCH 14/14] linting --- commit/chainfee/types.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/commit/chainfee/types.go b/commit/chainfee/types.go index 6082af961..fb299694e 100644 --- a/commit/chainfee/types.go +++ b/commit/chainfee/types.go @@ -60,5 +60,6 @@ func (n NoopMetrics) TrackChainFeeObservation(Observation) {} func (n NoopMetrics) TrackChainFeeOutcome(Outcome) {} func (o Observation) IsEmpty() bool { - return len(o.FeeComponents) == 0 && len(o.NativeTokenPrices) == 0 && len(o.ChainFeeUpdates) == 0 && len(o.FChain) == 0 && o.TimestampNow.IsZero() + return len(o.FeeComponents) == 0 && len(o.NativeTokenPrices) == 0 && len(o.ChainFeeUpdates) == 0 && + len(o.FChain) == 0 && o.TimestampNow.IsZero() }