From 74e74699275e7146ec56091ef785f5feec0d798a Mon Sep 17 00:00:00 2001 From: defistar Date: Thu, 4 Jul 2024 16:53:08 +0530 Subject: [PATCH 01/16] feat: CCIP-2594 modify the getAllChainConfigs function call from smartcontract with pagination based logic --- commit/plugin_e2e_test.go | 7 ++++-- internal/reader/home_chain.go | 41 ++++++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/commit/plugin_e2e_test.go b/commit/plugin_e2e_test.go index 669469497..65a0331ce 100644 --- a/commit/plugin_e2e_test.go +++ b/commit/plugin_e2e_test.go @@ -408,8 +408,11 @@ func setupHomeChainPoller(lggr logger.Logger, chainConfigInfos []reader.ChainCon mock.Anything, consts.ContractNameCCIPConfig, consts.MethodNameGetAllChainConfigs, - mock.Anything, - mock.Anything, + mock.MatchedBy(func(input map[string]interface{}) bool { + _, pageIndexExists := input["pageIndex"] + _, pageSizeExists := input["pageSize"] + return pageIndexExists && pageSizeExists + }), mock.Anything, ).Run( func(args mock.Arguments) { diff --git a/internal/reader/home_chain.go b/internal/reader/home_chain.go index 0f63cc5d5..e85d1b9eb 100644 --- a/internal/reader/home_chain.go +++ b/internal/reader/home_chain.go @@ -115,24 +115,39 @@ func (r *homeChainPoller) poll() { } func (r *homeChainPoller) fetchAndSetConfigs(ctx context.Context) error { - var chainConfigInfos []ChainConfigInfo - err := r.homeChainReader.GetLatestValue( - ctx, - consts.ContractNameCCIPConfig, - consts.MethodNameGetAllChainConfigs, - primitives.Unconfirmed, - nil, - &chainConfigInfos, - ) - if err != nil { - return err + var allChainConfigInfos []ChainConfigInfo + pageIndex := uint64(0) + pageSize := uint64(500) + + for { + var chainConfigInfos []ChainConfigInfo + err := r.homeChainReader.GetLatestValue( + ctx, + "CCIPConfig", + "getAllChainConfigs", + primitives.Unconfirmed, + map[string]interface{}{ + "pageIndex": pageIndex, + "pageSize": pageSize, + }, + &chainConfigInfos, + ) + if err != nil { + return err + } + if len(chainConfigInfos) == 0 { + break + } + allChainConfigInfos = append(allChainConfigInfos, chainConfigInfos...) + pageIndex++ } - if len(chainConfigInfos) == 0 { + + if len(allChainConfigInfos) == 0 { // That's a legitimate case if there are no chain configs on chain yet r.lggr.Warnw("no on chain configs found") return nil } - r.setState(convertOnChainConfigToHomeChainConfig(chainConfigInfos)) + r.setState(convertOnChainConfigToHomeChainConfig(allChainConfigInfos)) return nil } From c11a9aa5c465ed05d472237ff765243e8636983f Mon Sep 17 00:00:00 2001 From: defistar Date: Fri, 12 Jul 2024 20:32:47 +0530 Subject: [PATCH 02/16] fix: CCIP-2594 fix commit and execute plugin e2e and unit-tests to cater the changes for getAllConfigs function --- execute/plugin_e2e_test.go | 6 +++++- internal/reader/home_chain.go | 13 ++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/execute/plugin_e2e_test.go b/execute/plugin_e2e_test.go index 105959cc8..e78b6038c 100644 --- a/execute/plugin_e2e_test.go +++ b/execute/plugin_e2e_test.go @@ -84,7 +84,11 @@ func setupHomeChainPoller(lggr logger.Logger, chainConfigInfos []reader.ChainCon consts.ContractNameCCIPConfig, consts.MethodNameGetAllChainConfigs, mock.Anything, - mock.Anything, + mock.MatchedBy(func(input map[string]interface{}) bool { + _, pageIndexExists := input["pageIndex"] + _, pageSizeExists := input["pageSize"] + return pageIndexExists && pageSizeExists + }), mock.Anything, ).Run( func(args mock.Arguments) { diff --git a/internal/reader/home_chain.go b/internal/reader/home_chain.go index e85d1b9eb..0ce721497 100644 --- a/internal/reader/home_chain.go +++ b/internal/reader/home_chain.go @@ -20,6 +20,10 @@ import ( ) //go:generate mockery --name HomeChain --output ./mocks/ --case underscore +const ( + PageSize = uint64(500) +) + type HomeChain interface { GetChainConfig(chainSelector cciptypes.ChainSelector) (ChainConfig, error) GetAllChainConfigs() (map[cciptypes.ChainSelector]ChainConfig, error) @@ -117,7 +121,6 @@ func (r *homeChainPoller) poll() { func (r *homeChainPoller) fetchAndSetConfigs(ctx context.Context) error { var allChainConfigInfos []ChainConfigInfo pageIndex := uint64(0) - pageSize := uint64(500) for { var chainConfigInfos []ChainConfigInfo @@ -128,7 +131,7 @@ func (r *homeChainPoller) fetchAndSetConfigs(ctx context.Context) error { primitives.Unconfirmed, map[string]interface{}{ "pageIndex": pageIndex, - "pageSize": pageSize, + "pageSize": PageSize, }, &chainConfigInfos, ) @@ -217,9 +220,9 @@ func (r *homeChainPoller) GetOCRConfigs( consts.MethodNameGetOCRConfig, primitives.Unconfirmed, map[string]any{ - "donId": donID, - "pluginType": pluginType, - }, &ocrConfigs) + "donId": donID, + "pluginType": pluginType, + }, &ocrConfigs) if err != nil { return nil, fmt.Errorf("error fetching OCR configs: %w", err) } From c27f9978f401fd18819bb9614f86396369286085 Mon Sep 17 00:00:00 2001 From: defistar Date: Wed, 17 Jul 2024 00:03:13 +0530 Subject: [PATCH 03/16] fix: CCIP-2594 fix failing paginagtion tests on ccipConfig --- commit/plugin_e2e_test.go | 9 +++++++-- execute/plugin_e2e_test.go | 8 +++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/commit/plugin_e2e_test.go b/commit/plugin_e2e_test.go index 65a0331ce..abdae9397 100644 --- a/commit/plugin_e2e_test.go +++ b/commit/plugin_e2e_test.go @@ -22,7 +22,6 @@ import ( helpers "github.com/smartcontractkit/chainlink-ccip/internal/libs/testhelpers" "github.com/smartcontractkit/chainlink-ccip/internal/mocks" "github.com/smartcontractkit/chainlink-ccip/internal/reader" - "github.com/smartcontractkit/chainlink-ccip/pkg/consts" "github.com/smartcontractkit/chainlink-ccip/pluginconfig" "github.com/smartcontractkit/chainlink-ccip/plugintypes" ) @@ -403,6 +402,7 @@ func newNode( func setupHomeChainPoller(lggr logger.Logger, chainConfigInfos []reader.ChainConfigInfo) reader.HomeChain { homeChainReader := mocks.NewContractReaderMock() + var firstCall = true homeChainReader.On( "GetLatestValue", mock.Anything, @@ -417,7 +417,12 @@ func setupHomeChainPoller(lggr logger.Logger, chainConfigInfos []reader.ChainCon ).Run( func(args mock.Arguments) { arg := args.Get(5).(*[]reader.ChainConfigInfo) - *arg = chainConfigInfos + if firstCall { + *arg = chainConfigInfos + firstCall = false + } else { + *arg = []reader.ChainConfigInfo{} // return empty for other pages + } }).Return(nil) homeChain := reader.NewHomeChainConfigPoller( diff --git a/execute/plugin_e2e_test.go b/execute/plugin_e2e_test.go index e78b6038c..9f506bd89 100644 --- a/execute/plugin_e2e_test.go +++ b/execute/plugin_e2e_test.go @@ -78,6 +78,7 @@ type nodeSetup struct { func setupHomeChainPoller(lggr logger.Logger, chainConfigInfos []reader.ChainConfigInfo) reader.HomeChain { homeChainReader := mocks.NewContractReaderMock() + var firstCall = true homeChainReader.On( "GetLatestValue", mock.Anything, @@ -93,7 +94,12 @@ func setupHomeChainPoller(lggr logger.Logger, chainConfigInfos []reader.ChainCon ).Run( func(args mock.Arguments) { arg := args.Get(5).(*[]reader.ChainConfigInfo) - *arg = chainConfigInfos + if firstCall { + *arg = chainConfigInfos + firstCall = false + } else { + *arg = []reader.ChainConfigInfo{} // return empty for other pages + } }).Return(nil) homeChain := reader.NewHomeChainConfigPoller( From a6931278f8f71f2b6742f16ebee9cbb28071b61b Mon Sep 17 00:00:00 2001 From: defistar Date: Wed, 17 Jul 2024 00:23:31 +0530 Subject: [PATCH 04/16] feat: CCIP-2594 config-pagination output can be set to state even in case of empty results --- internal/reader/home_chain.go | 6 +++++- internal/reader/mocks/home_chain.go | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/internal/reader/home_chain.go b/internal/reader/home_chain.go index 0ce721497..00212f83d 100644 --- a/internal/reader/home_chain.go +++ b/internal/reader/home_chain.go @@ -145,12 +145,16 @@ func (r *homeChainPoller) fetchAndSetConfigs(ctx context.Context) error { pageIndex++ } + if len(allChainConfigInfos) >= 0 { + r.setState(convertOnChainConfigToHomeChainConfig(allChainConfigInfos)) + } + if len(allChainConfigInfos) == 0 { // That's a legitimate case if there are no chain configs on chain yet r.lggr.Warnw("no on chain configs found") return nil } - r.setState(convertOnChainConfigToHomeChainConfig(allChainConfigInfos)) + return nil } diff --git a/internal/reader/mocks/home_chain.go b/internal/reader/mocks/home_chain.go index 62239f01d..11d5af969 100644 --- a/internal/reader/mocks/home_chain.go +++ b/internal/reader/mocks/home_chain.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.43.0. DO NOT EDIT. +// Code generated by mockery v2.43.2. DO NOT EDIT. package mocks From 7fcacb7124eb1827f76290dd5226e4b11d3deb4d Mon Sep 17 00:00:00 2001 From: defistar Date: Wed, 17 Jul 2024 09:03:23 +0530 Subject: [PATCH 05/16] fix: CCIp-2594 fix failing homePoller Tests which asserts the calls on getAllChainConfigs --- internal/reader/home_chain.go | 2 ++ internal/reader/home_chain_test.go | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/internal/reader/home_chain.go b/internal/reader/home_chain.go index 00212f83d..22cea3541 100644 --- a/internal/reader/home_chain.go +++ b/internal/reader/home_chain.go @@ -138,9 +138,11 @@ func (r *homeChainPoller) fetchAndSetConfigs(ctx context.Context) error { if err != nil { return err } + if len(chainConfigInfos) == 0 { break } + allChainConfigInfos = append(allChainConfigInfos, chainConfigInfos...) pageIndex++ } diff --git a/internal/reader/home_chain_test.go b/internal/reader/home_chain_test.go index 855c2ea53..34f3dfaec 100644 --- a/internal/reader/home_chain_test.go +++ b/internal/reader/home_chain_test.go @@ -10,8 +10,6 @@ import ( libocrtypes "github.com/smartcontractkit/libocr/ragep2p/types" "github.com/smartcontractkit/chainlink-ccip/internal/mocks" - "github.com/smartcontractkit/chainlink-ccip/pkg/consts" - "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -117,6 +115,7 @@ func Test_PollingWorking(t *testing.T) { } homeChainReader := mocks.NewContractReaderMock() + var firstCall = true homeChainReader.On( "GetLatestValue", mock.Anything, @@ -128,14 +127,19 @@ func Test_PollingWorking(t *testing.T) { ).Run( func(args mock.Arguments) { arg := args.Get(5).(*[]ChainConfigInfo) - *arg = onChainConfigs + if firstCall { + *arg = onChainConfigs + firstCall = false + } else { + *arg = []ChainConfigInfo{} // return empty for other pages + } }).Return(nil) defer homeChainReader.AssertExpectations(t) var ( tickTime = 2 * time.Millisecond - totalSleepTime = tickTime * 4 + totalSleepTime = tickTime * 0 ) configPoller := NewHomeChainConfigPoller( From a5552515aa51cf85214287653956d5a577cb69f7 Mon Sep 17 00:00:00 2001 From: defistar Date: Tue, 30 Jul 2024 02:34:39 +0530 Subject: [PATCH 06/16] fix: CCIP-2594 fix dependency issue for tests --- internal/reader/home_chain_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/reader/home_chain_test.go b/internal/reader/home_chain_test.go index 34f3dfaec..0fdca96f7 100644 --- a/internal/reader/home_chain_test.go +++ b/internal/reader/home_chain_test.go @@ -10,6 +10,8 @@ import ( libocrtypes "github.com/smartcontractkit/libocr/ragep2p/types" "github.com/smartcontractkit/chainlink-ccip/internal/mocks" + "github.com/smartcontractkit/chainlink-ccip/pkg/consts" + "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/chainlink-common/pkg/logger" From 505afe33963575ec650d798e103336f15d07044c Mon Sep 17 00:00:00 2001 From: defistar Date: Tue, 30 Jul 2024 02:35:15 +0530 Subject: [PATCH 07/16] fix: CCIP-2594 fix dependency issue for tests --- internal/reader/home_chain_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/reader/home_chain_test.go b/internal/reader/home_chain_test.go index 0fdca96f7..153433727 100644 --- a/internal/reader/home_chain_test.go +++ b/internal/reader/home_chain_test.go @@ -16,7 +16,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" - "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) From 1c9448100ba264dd2e59252b7f32ae7f70cbfac4 Mon Sep 17 00:00:00 2001 From: defistar Date: Tue, 30 Jul 2024 02:39:43 +0530 Subject: [PATCH 08/16] fix: CCIP-2594 commit plugin tests --- commit/plugin_e2e_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/commit/plugin_e2e_test.go b/commit/plugin_e2e_test.go index abdae9397..c76c4f131 100644 --- a/commit/plugin_e2e_test.go +++ b/commit/plugin_e2e_test.go @@ -22,6 +22,7 @@ import ( helpers "github.com/smartcontractkit/chainlink-ccip/internal/libs/testhelpers" "github.com/smartcontractkit/chainlink-ccip/internal/mocks" "github.com/smartcontractkit/chainlink-ccip/internal/reader" + "github.com/smartcontractkit/chainlink-ccip/pkg/consts" "github.com/smartcontractkit/chainlink-ccip/pluginconfig" "github.com/smartcontractkit/chainlink-ccip/plugintypes" ) From 170ba79c8efccf68f70c56cd13df233b9a8c4f27 Mon Sep 17 00:00:00 2001 From: defistar Date: Tue, 30 Jul 2024 07:47:28 +0530 Subject: [PATCH 09/16] fix: CCIP-2594 commit plugin fix for ccip-config paginated query test --- commit/plugin_e2e_test.go | 1 + internal/reader/home_chain.go | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/commit/plugin_e2e_test.go b/commit/plugin_e2e_test.go index c76c4f131..8222da0f7 100644 --- a/commit/plugin_e2e_test.go +++ b/commit/plugin_e2e_test.go @@ -409,6 +409,7 @@ func setupHomeChainPoller(lggr logger.Logger, chainConfigInfos []reader.ChainCon mock.Anything, consts.ContractNameCCIPConfig, consts.MethodNameGetAllChainConfigs, + mock.Anything, mock.MatchedBy(func(input map[string]interface{}) bool { _, pageIndexExists := input["pageIndex"] _, pageSizeExists := input["pageSize"] diff --git a/internal/reader/home_chain.go b/internal/reader/home_chain.go index 22cea3541..cec95e14f 100644 --- a/internal/reader/home_chain.go +++ b/internal/reader/home_chain.go @@ -19,7 +19,6 @@ import ( "github.com/smartcontractkit/chainlink-ccip/pkg/consts" ) -//go:generate mockery --name HomeChain --output ./mocks/ --case underscore const ( PageSize = uint64(500) ) @@ -126,8 +125,8 @@ func (r *homeChainPoller) fetchAndSetConfigs(ctx context.Context) error { var chainConfigInfos []ChainConfigInfo err := r.homeChainReader.GetLatestValue( ctx, - "CCIPConfig", - "getAllChainConfigs", + consts.ContractNameCCIPConfig, + consts.MethodNameGetAllChainConfigs, primitives.Unconfirmed, map[string]interface{}{ "pageIndex": pageIndex, @@ -226,9 +225,9 @@ func (r *homeChainPoller) GetOCRConfigs( consts.MethodNameGetOCRConfig, primitives.Unconfirmed, map[string]any{ - "donId": donID, - "pluginType": pluginType, - }, &ocrConfigs) + "donId": donID, + "pluginType": pluginType, + }, &ocrConfigs) if err != nil { return nil, fmt.Errorf("error fetching OCR configs: %w", err) } From 87753bb687a4858efd824bf61b2ce8bfbb9713f4 Mon Sep 17 00:00:00 2001 From: defistar Date: Tue, 30 Jul 2024 15:03:47 +0530 Subject: [PATCH 10/16] fix: CCIP-2594 remove redundant length check on queried CCIPConfig --- internal/reader/home_chain.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/internal/reader/home_chain.go b/internal/reader/home_chain.go index cec95e14f..02bb8d11f 100644 --- a/internal/reader/home_chain.go +++ b/internal/reader/home_chain.go @@ -146,9 +146,7 @@ func (r *homeChainPoller) fetchAndSetConfigs(ctx context.Context) error { pageIndex++ } - if len(allChainConfigInfos) >= 0 { - r.setState(convertOnChainConfigToHomeChainConfig(allChainConfigInfos)) - } + r.setState(convertOnChainConfigToHomeChainConfig(allChainConfigInfos)) if len(allChainConfigInfos) == 0 { // That's a legitimate case if there are no chain configs on chain yet From b7ba83994f645eb37a59fbeb15f00de384231beb Mon Sep 17 00:00:00 2001 From: defistar Date: Tue, 30 Jul 2024 19:39:03 +0530 Subject: [PATCH 11/16] fix: CCIP-2594 Pagination hardLimits for pageIndex and PageSize --- internal/reader/home_chain.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/internal/reader/home_chain.go b/internal/reader/home_chain.go index 02bb8d11f..7e8f77591 100644 --- a/internal/reader/home_chain.go +++ b/internal/reader/home_chain.go @@ -20,7 +20,8 @@ import ( ) const ( - PageSize = uint64(500) + defaultConfigPageSize = uint64(10) + pageIndexHardLimit = 100 ) type HomeChain interface { @@ -121,7 +122,7 @@ func (r *homeChainPoller) fetchAndSetConfigs(ctx context.Context) error { var allChainConfigInfos []ChainConfigInfo pageIndex := uint64(0) - for { + for pageIndex < pageIndexHardLimit { var chainConfigInfos []ChainConfigInfo err := r.homeChainReader.GetLatestValue( ctx, @@ -130,12 +131,12 @@ func (r *homeChainPoller) fetchAndSetConfigs(ctx context.Context) error { primitives.Unconfirmed, map[string]interface{}{ "pageIndex": pageIndex, - "pageSize": PageSize, + "pageSize": defaultConfigPageSize, }, &chainConfigInfos, ) if err != nil { - return err + return fmt.Errorf("get config index:%d pagesize:%d: %w", pageIndex, defaultConfigPageSize, err) } if len(chainConfigInfos) == 0 { @@ -146,6 +147,10 @@ func (r *homeChainPoller) fetchAndSetConfigs(ctx context.Context) error { pageIndex++ } + if pageIndex >= pageIndexHardLimit { + r.lggr.Warnw("pageIndex hard limit reached or exceeded", "limit", pageIndexHardLimit) + } + r.setState(convertOnChainConfigToHomeChainConfig(allChainConfigInfos)) if len(allChainConfigInfos) == 0 { From 73a0f3a6b8bf4b7e86be2c7d65a18712ab67443e Mon Sep 17 00:00:00 2001 From: defistar Date: Tue, 30 Jul 2024 20:07:51 +0530 Subject: [PATCH 12/16] fix: CCIP-2594 go:generate mock generator command added at the HomeChain interface type --- internal/reader/home_chain.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/reader/home_chain.go b/internal/reader/home_chain.go index 7e8f77591..ff5f425f9 100644 --- a/internal/reader/home_chain.go +++ b/internal/reader/home_chain.go @@ -24,6 +24,7 @@ const ( pageIndexHardLimit = 100 ) +//go:generate mockery --name HomeChain --output ./mocks/ --case underscore type HomeChain interface { GetChainConfig(chainSelector cciptypes.ChainSelector) (ChainConfig, error) GetAllChainConfigs() (map[cciptypes.ChainSelector]ChainConfig, error) From 5bbd1785caa23ea762eb7a101560739d01274bbe Mon Sep 17 00:00:00 2001 From: defistar Date: Wed, 31 Jul 2024 15:23:45 +0530 Subject: [PATCH 13/16] fix: CCIP-2594 dev comments for max cap on pageIndex used for paginated query on CCIPConfig --- internal/reader/home_chain.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/reader/home_chain.go b/internal/reader/home_chain.go index ff5f425f9..619db7dec 100644 --- a/internal/reader/home_chain.go +++ b/internal/reader/home_chain.go @@ -21,7 +21,10 @@ import ( const ( defaultConfigPageSize = uint64(10) - pageIndexHardLimit = 100 + // pageIndexHardLimit is the maximum number of pages that the poller will fetch + // this is set as 500 so that we can get 5000 chainConfigs with in 500 rpc calls and + // maximum time for all rpc calls is around 150 seconds + pageIndexHardLimit = 500 ) //go:generate mockery --name HomeChain --output ./mocks/ --case underscore From b958ca98993c67edbfff612702db50e66683889b Mon Sep 17 00:00:00 2001 From: defistar Date: Thu, 1 Aug 2024 16:21:58 +0530 Subject: [PATCH 14/16] fix: CCIP-2594 pagination caps updated --- internal/reader/home_chain.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/reader/home_chain.go b/internal/reader/home_chain.go index 619db7dec..b174cb97b 100644 --- a/internal/reader/home_chain.go +++ b/internal/reader/home_chain.go @@ -20,11 +20,11 @@ import ( ) const ( - defaultConfigPageSize = uint64(10) + defaultConfigPageSize = uint64(100) // pageIndexHardLimit is the maximum number of pages that the poller will fetch - // this is set as 500 so that we can get 5000 chainConfigs with in 500 rpc calls and - // maximum time for all rpc calls is around 150 seconds - pageIndexHardLimit = 500 + // this is set as 1 so that we can get 100 chainConfigs with in 1 rpc call + // this can be increased once total chains reach 100 or more. + pageIndexHardLimit = 1 ) //go:generate mockery --name HomeChain --output ./mocks/ --case underscore From d6652032bc093b4793c6a0dcc99b204158f3e04c Mon Sep 17 00:00:00 2001 From: defistar Date: Mon, 12 Aug 2024 03:11:37 +0530 Subject: [PATCH 15/16] fix: CCIP-2594 CCIPConfig Pagination refactoring conflict resolution with ccip-develop --- go.mod | 5 +++-- go.sum | 3 +++ internal/reader/home_chain.go | 26 ++++++++++++++++++-------- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 9676e2e2a..e3894f4ce 100644 --- a/go.mod +++ b/go.mod @@ -9,8 +9,9 @@ require ( github.com/stretchr/testify v1.9.0 go.uber.org/zap v1.26.0 golang.org/x/crypto v0.24.0 + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/sync v0.7.0 - google.golang.org/grpc v1.64.0 + google.golang.org/grpc v1.64.1 ) require ( @@ -39,7 +40,7 @@ require ( github.com/stretchr/objx v0.5.2 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/net v0.25.0 // indirect + golang.org/x/net v0.26.0 // indirect golang.org/x/sys v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 // indirect diff --git a/go.sum b/go.sum index 64236a79c..a599e3a33 100644 --- a/go.sum +++ b/go.sum @@ -79,8 +79,10 @@ go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= @@ -94,6 +96,7 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/reader/home_chain.go b/internal/reader/home_chain.go index b174cb97b..cbddba4a8 100644 --- a/internal/reader/home_chain.go +++ b/internal/reader/home_chain.go @@ -16,6 +16,7 @@ import ( cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" + "github.com/smartcontractkit/chainlink-ccip/chainconfig" "github.com/smartcontractkit/chainlink-ccip/pkg/consts" ) @@ -155,7 +156,7 @@ func (r *homeChainPoller) fetchAndSetConfigs(ctx context.Context) error { r.lggr.Warnw("pageIndex hard limit reached or exceeded", "limit", pageIndexHardLimit) } - r.setState(convertOnChainConfigToHomeChainConfig(allChainConfigInfos)) + r.setState(convertOnChainConfigToHomeChainConfig(r.lggr, allChainConfigInfos)) if len(allChainConfigInfos) == 0 { // That's a legitimate case if there are no chain configs on chain yet @@ -301,15 +302,24 @@ func createNodesSupportedChains( return nodeSupportedChains } -func convertOnChainConfigToHomeChainConfig(capabilityCfgs []ChainConfigInfo) map[cciptypes.ChainSelector]ChainConfig { +func convertOnChainConfigToHomeChainConfig( + lggr logger.Logger, + chainConfigInfos []ChainConfigInfo, +) map[cciptypes.ChainSelector]ChainConfig { chainConfigs := make(map[cciptypes.ChainSelector]ChainConfig) - for _, capabilityConfig := range capabilityCfgs { - chainSelector := capabilityConfig.ChainSelector - config := capabilityConfig.ChainConfig + for _, chainConfigInfo := range chainConfigInfos { + chainSelector := chainConfigInfo.ChainSelector + chainConfig := chainConfigInfo.ChainConfig + decoded, err := chainconfig.DecodeChainConfig(chainConfig.Config) + if err != nil { + lggr.Warnw(fmt.Sprintf("failed to decode opaque chain config of chain selector %d", chainSelector), "err", err) + continue + } chainConfigs[chainSelector] = ChainConfig{ - FChain: int(config.FChain), - SupportedNodes: mapset.NewSet(config.Readers...), + FChain: int(chainConfig.FChain), + SupportedNodes: mapset.NewSet(chainConfig.Readers...), + Config: decoded, } } return chainConfigs @@ -340,7 +350,7 @@ type ChainConfig struct { // SupportedNodes is a map of PeerIDs to SupportedChains. SupportedNodes mapset.Set[libocrtypes.PeerID] `json:"supportedNodes"` // Config is the chain specific configuration. - Config []byte `json:"config"` + Config chainconfig.ChainConfig `json:"config"` } // OCR3Config mirrors CCIPConfig.sol's OCR3Config struct From 595aa8332f4c47b336caff572ad8ef43a90ed728 Mon Sep 17 00:00:00 2001 From: defistar Date: Mon, 12 Aug 2024 03:35:17 +0530 Subject: [PATCH 16/16] fix: CCIP-2594 Conflict resolution with base branch --- chainconfig/chainconfig.go | 68 +++++++++++++++++++++++ chainconfig/chainconfig_test.go | 86 ++++++++++++++++++++++++++++++ go.sum | 6 +-- internal/reader/home_chain.go | 28 +++------- internal/reader/home_chain_test.go | 16 ++++-- 5 files changed, 177 insertions(+), 27 deletions(-) create mode 100644 chainconfig/chainconfig.go create mode 100644 chainconfig/chainconfig_test.go diff --git a/chainconfig/chainconfig.go b/chainconfig/chainconfig.go new file mode 100644 index 000000000..e52fc6b30 --- /dev/null +++ b/chainconfig/chainconfig.go @@ -0,0 +1,68 @@ +package chainconfig + +import ( + "encoding/json" + "errors" + "math/big" + + cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" +) + +// ChainConfig holds configuration that is stored in the onchain CCIPConfig.sol +// configuration contract, specifically the `bytes config` field of the ChainConfig +// solidity struct. +type ChainConfig struct { + // GasPriceDeviationPPB is the maximum deviation in parts per billion that the + // gas price of this chain is allowed to deviate from the last written gas price + // on-chain before we write a new gas price. + GasPriceDeviationPPB cciptypes.BigInt `json:"gasPriceDeviationPPB"` + + // DAGasPriceDeviationPPB is the maximum deviation in parts per billion that the + // data-availability gas price of this chain is allowed to deviate from the last + // written data-availability gas price on-chain before we write a new data-availability + // gas price. + // This is only applicable for some chains, such as L2's. + DAGasPriceDeviationPPB cciptypes.BigInt `json:"daGasPriceDeviationPPB"` + + // FinalityDepth is the number of confirmations before a block is considered finalized. + // If set to -1, finality tags will be used. + // 0 is not a valid value. + FinalityDepth int64 `json:"finalityDepth"` + + // OptimisticConfirmations is the number of confirmations of a chain event before + // it is considered optimistically confirmed (i.e not necessarily finalized). + OptimisticConfirmations uint32 `json:"optimisticConfirmations"` +} + +func (cc ChainConfig) Validate() error { + if cc.GasPriceDeviationPPB.Int.Cmp(big.NewInt(0)) <= 0 { + return errors.New("GasPriceDeviationPPB not set or negative") + } + + // No validation for DAGasPriceDeviationPPB as it is optional + // and only applicable to L2's. + + if cc.FinalityDepth == 0 { + return errors.New("FinalityDepth not set") + } + + if cc.OptimisticConfirmations == 0 { + return errors.New("OptimisticConfirmations not set") + } + + return nil +} + +// EncodeChainConfig encodes a ChainConfig into bytes using JSON. +func EncodeChainConfig(cc ChainConfig) ([]byte, error) { + return json.Marshal(cc) +} + +// DecodeChainConfig JSON decodes a ChainConfig from bytes. +func DecodeChainConfig(encodedChainConfig []byte) (ChainConfig, error) { + var cc ChainConfig + if err := json.Unmarshal(encodedChainConfig, &cc); err != nil { + return cc, err + } + return cc, nil +} diff --git a/chainconfig/chainconfig_test.go b/chainconfig/chainconfig_test.go new file mode 100644 index 000000000..033d18077 --- /dev/null +++ b/chainconfig/chainconfig_test.go @@ -0,0 +1,86 @@ +package chainconfig + +import ( + "math/big" + "testing" + + cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" +) + +func TestChainConfig_Validate(t *testing.T) { + type fields struct { + GasPriceDeviationPPB cciptypes.BigInt + DAGasPriceDeviationPPB cciptypes.BigInt + FinalityDepth int64 + OptimisticConfirmations uint32 + } + tests := []struct { + name string + fields fields + wantErr bool + }{ + { + "valid", + fields{ + GasPriceDeviationPPB: cciptypes.BigInt{Int: big.NewInt(1)}, + DAGasPriceDeviationPPB: cciptypes.BigInt{Int: big.NewInt(1)}, + FinalityDepth: 1, + OptimisticConfirmations: 1, + }, + false, + }, + { + "valid, finality tags enabled", + fields{ + GasPriceDeviationPPB: cciptypes.BigInt{Int: big.NewInt(1)}, + DAGasPriceDeviationPPB: cciptypes.BigInt{Int: big.NewInt(1)}, + FinalityDepth: -1, + OptimisticConfirmations: 1, + }, + false, + }, + { + "invalid, gas price deviation not set", + fields{ + GasPriceDeviationPPB: cciptypes.BigInt{Int: big.NewInt(0)}, + DAGasPriceDeviationPPB: cciptypes.BigInt{Int: big.NewInt(1)}, + FinalityDepth: 1, + OptimisticConfirmations: 1, + }, + true, + }, + { + "invalid, finality depth not set", + fields{ + GasPriceDeviationPPB: cciptypes.BigInt{Int: big.NewInt(1)}, + DAGasPriceDeviationPPB: cciptypes.BigInt{Int: big.NewInt(1)}, + FinalityDepth: 0, + OptimisticConfirmations: 1, + }, + true, + }, + { + "invalid, optimistic confirmations not set", + fields{ + GasPriceDeviationPPB: cciptypes.BigInt{Int: big.NewInt(1)}, + DAGasPriceDeviationPPB: cciptypes.BigInt{Int: big.NewInt(1)}, + FinalityDepth: 1, + OptimisticConfirmations: 0, + }, + true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cc := ChainConfig{ + GasPriceDeviationPPB: tt.fields.GasPriceDeviationPPB, + DAGasPriceDeviationPPB: tt.fields.DAGasPriceDeviationPPB, + FinalityDepth: tt.fields.FinalityDepth, + OptimisticConfirmations: tt.fields.OptimisticConfirmations, + } + if err := cc.Validate(); (err != nil) != tt.wantErr { + t.Errorf("ChainConfig.Validate() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/go.sum b/go.sum index a599e3a33..5ff7736c3 100644 --- a/go.sum +++ b/go.sum @@ -80,8 +80,7 @@ go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= @@ -94,8 +93,7 @@ gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0= gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU= google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 h1:Q2RxlXqh1cgzzUgV261vBO2jI5R/3DD1J2pM0nI4NhU= google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= diff --git a/internal/reader/home_chain.go b/internal/reader/home_chain.go index cbddba4a8..c98586d35 100644 --- a/internal/reader/home_chain.go +++ b/internal/reader/home_chain.go @@ -21,14 +21,9 @@ import ( ) const ( - defaultConfigPageSize = uint64(100) - // pageIndexHardLimit is the maximum number of pages that the poller will fetch - // this is set as 1 so that we can get 100 chainConfigs with in 1 rpc call - // this can be increased once total chains reach 100 or more. - pageIndexHardLimit = 1 + PageSize = uint64(500) ) -//go:generate mockery --name HomeChain --output ./mocks/ --case underscore type HomeChain interface { GetChainConfig(chainSelector cciptypes.ChainSelector) (ChainConfig, error) GetAllChainConfigs() (map[cciptypes.ChainSelector]ChainConfig, error) @@ -126,44 +121,37 @@ func (r *homeChainPoller) poll() { func (r *homeChainPoller) fetchAndSetConfigs(ctx context.Context) error { var allChainConfigInfos []ChainConfigInfo pageIndex := uint64(0) + pageSize := uint64(500) - for pageIndex < pageIndexHardLimit { + for { var chainConfigInfos []ChainConfigInfo err := r.homeChainReader.GetLatestValue( ctx, - consts.ContractNameCCIPConfig, - consts.MethodNameGetAllChainConfigs, + "CCIPConfig", + "GetAllChainConfigs", primitives.Unconfirmed, map[string]interface{}{ "pageIndex": pageIndex, - "pageSize": defaultConfigPageSize, + "pageSize": pageSize, }, &chainConfigInfos, ) if err != nil { - return fmt.Errorf("get config index:%d pagesize:%d: %w", pageIndex, defaultConfigPageSize, err) + return err } - if len(chainConfigInfos) == 0 { break } - allChainConfigInfos = append(allChainConfigInfos, chainConfigInfos...) pageIndex++ } - if pageIndex >= pageIndexHardLimit { - r.lggr.Warnw("pageIndex hard limit reached or exceeded", "limit", pageIndexHardLimit) - } - - r.setState(convertOnChainConfigToHomeChainConfig(r.lggr, allChainConfigInfos)) - if len(allChainConfigInfos) == 0 { // That's a legitimate case if there are no chain configs on chain yet r.lggr.Warnw("no on chain configs found") return nil } - + r.setState(convertOnChainConfigToHomeChainConfig(r.lggr, allChainConfigInfos)) return nil } diff --git a/internal/reader/home_chain_test.go b/internal/reader/home_chain_test.go index 153433727..1e05fe157 100644 --- a/internal/reader/home_chain_test.go +++ b/internal/reader/home_chain_test.go @@ -9,6 +9,7 @@ import ( mapset "github.com/deckarep/golang-set/v2" libocrtypes "github.com/smartcontractkit/libocr/ragep2p/types" + "github.com/smartcontractkit/chainlink-ccip/chainconfig" "github.com/smartcontractkit/chainlink-ccip/internal/mocks" "github.com/smartcontractkit/chainlink-ccip/pkg/consts" @@ -16,6 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) @@ -65,6 +67,11 @@ func TestHomeChainConfigPoller_HealthReport(t *testing.T) { } func Test_PollingWorking(t *testing.T) { + chainConfig := chainconfig.ChainConfig{ + FinalityDepth: 1, + } + encodedChainConfig, err := chainconfig.EncodeChainConfig(chainConfig) + require.NoError(t, err) onChainConfigs := []ChainConfigInfo{ { ChainSelector: chainA, @@ -75,7 +82,7 @@ func Test_PollingWorking(t *testing.T) { p2pOracleBId, p2pOracleCId, }, - Config: []byte{0}, + Config: encodedChainConfig, }, }, { @@ -86,7 +93,7 @@ func Test_PollingWorking(t *testing.T) { p2pOracleAId, p2pOracleBId, }, - Config: []byte{0}, + Config: encodedChainConfig, }, }, { @@ -96,7 +103,7 @@ func Test_PollingWorking(t *testing.T) { Readers: []libocrtypes.PeerID{ p2pOracleCId, }, - Config: []byte{0}, + Config: encodedChainConfig, }, }, } @@ -104,14 +111,17 @@ func Test_PollingWorking(t *testing.T) { chainA: { FChain: 1, SupportedNodes: mapset.NewSet(p2pOracleAId, p2pOracleBId, p2pOracleCId), + Config: chainConfig, }, chainB: { FChain: 2, SupportedNodes: mapset.NewSet(p2pOracleAId, p2pOracleBId), + Config: chainConfig, }, chainC: { FChain: 3, SupportedNodes: mapset.NewSet(p2pOracleCId), + Config: chainConfig, }, }