Skip to content

Commit

Permalink
add fchain validation for fee token observation (#308)
Browse files Browse the repository at this point in the history
* add fchain validation for fee token observation

* update error message efor consistency

* goimport

* check that fchain addresses exist in observed chain

* boda comments
  • Loading branch information
0xAustinWang authored Nov 11, 2024
1 parent dd6fae4 commit 810e556
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 31 deletions.
6 changes: 3 additions & 3 deletions commit/merkleroot/validate_observation.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ func validateRMNRemoteConfig(
}

func validateFChain(fChain map[cciptypes.ChainSelector]int) error {
for _, f := range fChain {
if f < 0 {
return fmt.Errorf("fChain %d is negative", f)
for chainSelector, f := range fChain {
if f <= 0 {
return fmt.Errorf("fChain for chain %d is not positive: %d", chainSelector, f)
}
}

Expand Down
25 changes: 0 additions & 25 deletions commit/tokenprice/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"context"
"fmt"

mapset "github.com/deckarep/golang-set/v2"

"github.com/smartcontractkit/libocr/commontypes"

"github.com/smartcontractkit/chainlink-common/pkg/logger"
Expand Down Expand Up @@ -54,14 +52,6 @@ func (p *processor) Query(ctx context.Context, prevOutcome Outcome) (Query, erro
return Query{}, nil
}

func (p *processor) ValidateObservation(
prevOutcome Outcome,
query Query,
ao plugincommon.AttributedObservation[Observation],
) error {
return validateObservedTokenPrices(ao.Observation.FeedTokenPrices)
}

func (p *processor) Outcome(
ctx context.Context,
_ Outcome,
Expand Down Expand Up @@ -94,19 +84,4 @@ func (p *processor) Close() error {
return nil
}

func validateObservedTokenPrices(tokenPrices []cciptypes.TokenPrice) error {
tokensWithPrice := mapset.NewSet[cciptypes.UnknownEncodedAddress]()
for _, t := range tokenPrices {
if tokensWithPrice.Contains(t.TokenID) {
return fmt.Errorf("duplicate token price for token: %s", t.TokenID)
}
tokensWithPrice.Add(t.TokenID)

if t.Price.IsEmpty() {
return fmt.Errorf("token price of token %v must not be empty", t.TokenID)
}
}
return nil
}

var _ plugincommon.PluginProcessor[Query, Observation, Outcome] = &processor{}
64 changes: 64 additions & 0 deletions commit/tokenprice/validate_observation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package tokenprice

import (
"fmt"

mapset "github.com/deckarep/golang-set/v2"

"github.com/smartcontractkit/chainlink-ccip/internal/plugincommon"
cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3"
)

func (p *processor) ValidateObservation(
prevOutcome Outcome,
query Query,
ao plugincommon.AttributedObservation[Observation],
) error {
obs := ao.Observation

if err := validateFChain(obs.FChain); err != nil {
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)
}

for chain := range obs.FChain {
if !observerSupportedChains.Contains(chain) {
return fmt.Errorf("chain %d is not supported by observer", chain)
}
}

if err := validateObservedTokenPrices(obs.FeedTokenPrices); err != nil {
return fmt.Errorf("failed to validate observed token prices: %w", err)
}

return nil
}

func validateFChain(fChain map[cciptypes.ChainSelector]int) error {
for chainSelector, f := range fChain {
if f <= 0 {
return fmt.Errorf("fChain for chain %d is not positive: %d", chainSelector, f)
}
}

return nil
}

func validateObservedTokenPrices(tokenPrices []cciptypes.TokenPrice) error {
tokensWithPrice := mapset.NewSet[cciptypes.UnknownEncodedAddress]()
for _, t := range tokenPrices {
if tokensWithPrice.Contains(t.TokenID) {
return fmt.Errorf("duplicate token price for token: %s", t.TokenID)
}
tokensWithPrice.Add(t.TokenID)

if t.Price.IsEmpty() {
return fmt.Errorf("token price of token %v must not be empty", t.TokenID)
}
}
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,47 @@ func Test_validateObservedTokenPrices(t *testing.T) {

}
}

func Test_validateFChain(t *testing.T) {
testCases := []struct {
name string
fChain map[cciptypes.ChainSelector]int
expErr bool
}{
{
name: "FChain contains negative values",
fChain: map[cciptypes.ChainSelector]int{
1: 11,
2: -4,
},
expErr: true,
},
{
name: "FChain zero",
fChain: map[cciptypes.ChainSelector]int{
12: 0,
},
expErr: true,
},
{
name: "FChain valid",
fChain: map[cciptypes.ChainSelector]int{
12: 6,
7: 9,
},
expErr: false,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := validateFChain(tc.fChain)

if tc.expErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
})
}
}
6 changes: 3 additions & 3 deletions commit/validate_observation.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ func (p *Plugin) ValidateObservation(
}

func validateFChain(fChain map[cciptypes.ChainSelector]int) error {
for _, f := range fChain {
if f < 0 {
return fmt.Errorf("fChain %d is negative", f)
for chainSelector, f := range fChain {
if f <= 0 {
return fmt.Errorf("fChain for chain %d is not positive: %d", chainSelector, f)
}
}

Expand Down

0 comments on commit 810e556

Please sign in to comment.