Skip to content

Commit

Permalink
offchain - move price getter under internal/pricegetter (#143)
Browse files Browse the repository at this point in the history
  • Loading branch information
dimkouv authored Sep 16, 2023
1 parent 4483dc5 commit d75130d
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 82 deletions.
3 changes: 2 additions & 1 deletion core/services/ocr2/plugins/ccip/commit_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipevents"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/hashlib"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/oraclelib"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter"

"github.com/smartcontractkit/chainlink/v2/core/chains/evm"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
Expand Down Expand Up @@ -78,7 +79,7 @@ func NewCommitServices(lggr logger.Logger, jb job.Job, chainSet evm.LegacyChainC
if err != nil {
return nil, errors.Wrap(err, "failed loading onRamp")
}
priceGetterObject, err := NewPriceGetter(pluginConfig.TokenPricesUSDPipeline, pr, jb.ID, jb.ExternalJobID, jb.Name.ValueOrZero(), lggr)
priceGetterObject, err := pricegetter.NewPipelineGetter(pluginConfig.TokenPricesUSDPipeline, pr, jb.ID, jb.ExternalJobID, jb.Name.ValueOrZero(), lggr)
if err != nil {
return nil, err
}
Expand Down
3 changes: 2 additions & 1 deletion core/services/ocr2/plugins/ccip/commit_reporting_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"
ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter"

"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/cache"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipevents"
Expand Down Expand Up @@ -60,7 +61,7 @@ type CommitPluginConfig struct {
offRamp evm_2_evm_offramp.EVM2EVMOffRampInterface
onRampAddress common.Address
commitStore commit_store.CommitStoreInterface
priceGetter PriceGetter
priceGetter pricegetter.PriceGetter
sourceChainSelector uint64
sourceNative common.Address
sourceFeeEstimator gas.EvmFeeEstimator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipevents"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/hashlib"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/merklemulti"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter"
plugintesthelpers "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers/plugins"
"github.com/smartcontractkit/chainlink/v2/core/store/models"
"github.com/smartcontractkit/chainlink/v2/core/utils"
Expand Down Expand Up @@ -65,7 +66,7 @@ func setupCommitTestHarness(t *testing.T) commitTestHarness {
).Maybe().Return(gas.EvmFee{Legacy: assets.NewWei(defaultGasPrice)}, uint32(200e3), nil)

lggr := logger.TestLogger(t)
priceGetter := newMockPriceGetter()
priceGetter := pricegetter.NewMockPriceGetter(t)

backendClient := client.NewSimulatedBackendClient(t, th.Dest.Chain, new(big.Int).SetUint64(th.Dest.ChainID))
plugin := CommitReportingPlugin{
Expand Down Expand Up @@ -104,7 +105,7 @@ func setupCommitTestHarness(t *testing.T) commitTestHarness {
plugin.config.sourceNative: big.NewInt(0).Mul(big.NewInt(100), big.NewInt(1e18)),
th.Source.LinkToken.Address(): big.NewInt(0).Mul(big.NewInt(200), big.NewInt(1e18)),
th.Dest.LinkToken.Address(): big.NewInt(0).Mul(big.NewInt(200), big.NewInt(1e18)),
}, nil)
}, nil).Maybe()

return commitTestHarness{
CCIPPluginTestHarness: th,
Expand Down Expand Up @@ -782,7 +783,7 @@ func TestGeneratePriceUpdates(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
priceGetter := newMockPriceGetter()
priceGetter := pricegetter.NewMockPriceGetter(t)
defer priceGetter.AssertExpectations(t)

sourceFeeEstimator := mocks.NewEvmFeeEstimator(t)
Expand All @@ -796,7 +797,7 @@ func TestGeneratePriceUpdates(t *testing.T) {
sort.Slice(tokens, func(i, j int) bool { return tokens[i].String() < tokens[j].String() })

if len(tokens) > 0 {
priceGetter.On("TokenPricesUSD", tokens).Return(tc.priceGetterRespData, tc.priceGetterRespErr)
priceGetter.On("TokenPricesUSD", mock.Anything, tokens).Return(tc.priceGetterRespData, tc.priceGetterRespErr)
}

if tc.maxGasPrice > 0 {
Expand Down
44 changes: 44 additions & 0 deletions core/services/ocr2/plugins/ccip/internal/parseutil/bigint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package parseutil

import (
"math/big"

"github.com/pkg/errors"
"github.com/shopspring/decimal"
)

func ParseBigIntFromAny(val any) (*big.Int, error) {
if val == nil {
return nil, errors.Errorf("nil value passed")
}

switch v := val.(type) {
case decimal.Decimal:
return ParseBigIntFromString(v.String())
case *decimal.Decimal:
return ParseBigIntFromString(v.String())
case *big.Int:
return v, nil
case string:
return ParseBigIntFromString(v)
case int:
return big.NewInt(int64(v)), nil
case int64:
return big.NewInt(v), nil
case float64:
i := new(big.Int)
big.NewFloat(v).Int(i)
return i, nil
default:
return nil, errors.Errorf("unsupported big int type %T", val)
}
}

func ParseBigIntFromString(v string) (*big.Int, error) {
valBigInt, success := new(big.Int).SetString(v, 10)
if !success {
return nil, errors.Errorf("unable to convert to integer %s", v)
}

return valBigInt, nil
}
43 changes: 43 additions & 0 deletions core/services/ocr2/plugins/ccip/internal/parseutil/bigint_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package parseutil

import (
"math/big"
"testing"

"github.com/shopspring/decimal"
"github.com/stretchr/testify/assert"
)

func TestParseBigIntFromAny(t *testing.T) {
decimalVal := decimal.New(123, 0)

testCases := []struct {
name string
val any
res *big.Int
expErr bool
}{
{name: "nil", val: nil, expErr: true},
{name: "string", val: "123", res: big.NewInt(123)},
{name: "decimal", val: decimal.New(123, 0), res: big.NewInt(123)},
{name: "decimal pointer", val: &decimalVal, res: big.NewInt(123)},
{name: "int64", val: int64(123), res: big.NewInt(123)},
{name: "int", val: 123, res: big.NewInt(123)},
{name: "float", val: 123.12, res: big.NewInt(123)},
{name: "uint8", val: uint8(12), expErr: true},
{name: "struct", val: struct{ name string }{name: "asd"}, expErr: true},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
res, err := ParseBigIntFromAny(tc.val)
if tc.expErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tc.res, res)
})
}

}
58 changes: 58 additions & 0 deletions core/services/ocr2/plugins/ccip/internal/pricegetter/mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package ccip
package pricegetter

import (
"context"
Expand All @@ -8,20 +8,15 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/shopspring/decimal"

"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/parseutil"
"github.com/smartcontractkit/chainlink/v2/core/services/pipeline"
)

type PriceGetter interface {
// Returns token prices in USD
TokenPricesUSD(ctx context.Context, tokens []common.Address) (map[common.Address]*big.Int, error)
}

var _ PriceGetter = &priceGetter{}
var _ PriceGetter = &PipelineGetter{}

type priceGetter struct {
type PipelineGetter struct {
source string
runner pipeline.Runner
jobID int32
Expand All @@ -30,12 +25,13 @@ type priceGetter struct {
lggr logger.Logger
}

func NewPriceGetter(source string, runner pipeline.Runner, jobID int32, externalJobID uuid.UUID, name string, lggr logger.Logger) (*priceGetter, error) {
func NewPipelineGetter(source string, runner pipeline.Runner, jobID int32, externalJobID uuid.UUID, name string, lggr logger.Logger) (*PipelineGetter, error) {
_, err := pipeline.Parse(source)
if err != nil {
return nil, err
}
return &priceGetter{

return &PipelineGetter{
source: source,
runner: runner,
jobID: jobID,
Expand All @@ -45,7 +41,7 @@ func NewPriceGetter(source string, runner pipeline.Runner, jobID int32, external
}, nil
}

func (d *priceGetter) TokenPricesUSD(ctx context.Context, tokens []common.Address) (map[common.Address]*big.Int, error) {
func (d *PipelineGetter) TokenPricesUSD(ctx context.Context, tokens []common.Address) (map[common.Address]*big.Int, error) {
_, trrs, err := d.runner.ExecuteRun(ctx, pipeline.Spec{
ID: d.jobID,
DotDagSource: d.source,
Expand All @@ -71,7 +67,7 @@ func (d *priceGetter) TokenPricesUSD(ctx context.Context, tokens []common.Addres

priceMap := make(map[common.Address]*big.Int)
for tokenAddress, rawPrice := range prices {
castedPrice, err := parseBigInt(rawPrice)
castedPrice, err := parseutil.ParseBigIntFromAny(rawPrice)
if err != nil {
return nil, err
}
Expand All @@ -86,36 +82,3 @@ func (d *priceGetter) TokenPricesUSD(ctx context.Context, tokens []common.Addres
}
return priceMap, nil
}

func parseBigInt(price any) (*big.Int, error) {
if price == nil {
return nil, errors.Errorf("nil value passed")
}

switch v := price.(type) {
case decimal.Decimal:
return bigIntFromString(v.String())
case *decimal.Decimal:
return bigIntFromString(v.String())
case *big.Int:
return v, nil
case string:
return bigIntFromString(v)
case int64:
return big.NewInt(v), nil
case float64:
i := new(big.Int)
big.NewFloat(v).Int(i)
return i, nil
default:
return nil, errors.Errorf("unsupported price type %T from tokensForFeeCoin spec", price)
}
}

func bigIntFromString(v string) (*big.Int, error) {
priceBigInt, success := new(big.Int).SetString(v, 10)
if !success {
return nil, errors.Errorf("unable to convert to integer %v", v)
}
return priceBigInt, nil
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package ccip_test
package pricegetter_test

import (
"context"
Expand All @@ -16,6 +16,7 @@ import (

"github.com/smartcontractkit/chainlink/v2/core/bridges"
"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/pricegetter"
"github.com/smartcontractkit/chainlink/v2/core/services/pipeline"

pipelinemocks "github.com/smartcontractkit/chainlink/v2/core/services/pipeline/mocks"
Expand All @@ -24,7 +25,6 @@ import (

config "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2"
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip"
)

func TestDataSource(t *testing.T) {
Expand Down Expand Up @@ -52,7 +52,7 @@ func TestDataSource(t *testing.T) {
merge [type=merge left="{}" right="{\"%s\":$(link_parse), \"%s\":$(usdc_parse)}"];
`, linkEth.URL, usdcEth.URL, linkTokenAddress, usdcTokenAddress)

priceGetter := createPriceGetter(t, source)
priceGetter := newTestPipelineGetter(t, source)
// Ask for all prices present in spec.
prices, err := priceGetter.TokenPricesUSD(context.Background(), []common.Address{linkTokenAddress, usdcTokenAddress})
require.NoError(t, err)
Expand Down Expand Up @@ -125,7 +125,7 @@ func TestParsingDifferentFormats(t *testing.T) {
merge [type=merge left="{}" right="{\"%s\":$(coin_parse)}"];
`, token.URL, address)

prices, err := createPriceGetter(t, source).
prices, err := newTestPipelineGetter(t, source).
TokenPricesUSD(context.Background(), []common.Address{address})

if tt.expectedError {
Expand All @@ -138,7 +138,7 @@ func TestParsingDifferentFormats(t *testing.T) {
}
}

func createPriceGetter(t *testing.T, source string) ccip.PriceGetter {
func newTestPipelineGetter(t *testing.T, source string) *pricegetter.PipelineGetter {
lggr, _ := logger.NewLogger()
cfg := pipelinemocks.NewConfig(t)
cfg.On("MaxRunDuration").Return(time.Second)
Expand All @@ -148,7 +148,7 @@ func createPriceGetter(t *testing.T, source string) ccip.PriceGetter {
bridgeORM := bridges.NewORM(db, lggr, config.NewTestGeneralConfig(t).Database())
runner := pipeline.NewRunner(pipeline.NewORM(db, lggr, config.NewTestGeneralConfig(t).Database(), config.NewTestGeneralConfig(t).JobPipeline().MaxSuccessfulRuns()),
bridgeORM, cfg, nil, nil, nil, nil, lggr, &http.Client{}, &http.Client{})
ds, err := ccip.NewPriceGetter(source, runner, 1, uuid.New(), "test", lggr)
ds, err := pricegetter.NewPipelineGetter(source, runner, 1, uuid.New(), "test", lggr)
require.NoError(t, err)
return ds
}
Loading

0 comments on commit d75130d

Please sign in to comment.