From 6435646e6512250bdd83a57e20eb97ffb7ca3499 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Sun, 2 Feb 2025 15:00:49 +0400 Subject: [PATCH 01/35] test --- pkg/reader/ccip.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index a424f9bd4..be9e40c64 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -935,6 +935,8 @@ func (r *ccipChainReader) DiscoverContracts(ctx context.Context) (ContractAddres } } + r.lggr.Infow("discovered contracts", "contracts", resp) + // The following calls are on dynamically configured chains which may not // be available when this function is called. Eventually they will be // configured through consensus when the Sync function is called, but until From 6f10a7a21a1667a969b9df16738cf82ff034e6d4 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Sun, 2 Feb 2025 20:40:53 +0400 Subject: [PATCH 02/35] some logs --- pkg/reader/ccip.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index be9e40c64..63140fa0e 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -871,6 +871,8 @@ func (r *ccipChainReader) discoverOffRampContracts( return nil, fmt.Errorf("unable to get SourceChainsConfig: %w", err) } + r.lggr.Infow("sourceConfigs", "sourceConfigs", sourceConfigs) + // Iterate results in sourceChain selector order so that the router config is deterministic. keys := maps.Keys(sourceConfigs) sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] }) @@ -898,6 +900,9 @@ func (r *ccipChainReader) discoverOffRampContracts( if err != nil { return nil, fmt.Errorf("unable to lookup nonce manager and rmn proxy remote (offramp static config): %w", err) } + + lggr.Infow("got offramp static config", "staticConfig", staticConfig) + resp = resp.Append(consts.ContractNameNonceManager, chain, staticConfig.NonceManager) resp = resp.Append(consts.ContractNameRMNRemote, chain, staticConfig.RmnRemote) lggr.Infow("appending RMN remote contract address", "address", staticConfig.RmnRemote) @@ -916,6 +921,9 @@ func (r *ccipChainReader) discoverOffRampContracts( if err != nil { return nil, fmt.Errorf("unable to lookup fee quoter (offramp dynamic config): %w", err) } + + lggr.Infow("got offramp dynamic config", "dynamicConfig", dynamicConfig) + resp = resp.Append(consts.ContractNameFeeQuoter, chain, dynamicConfig.FeeQuoter) lggr.Infow("appending fee quoter contract address", "address", dynamicConfig.FeeQuoter) } @@ -1240,7 +1248,7 @@ func (r *ccipChainReader) getAllOffRampSourceChainsConfig( return nil, fmt.Errorf("selectors and source chain configs length mismatch: %v", resp) } - lggr.Debugw("got source chain configs", "configs", resp) + lggr.Infow("got source chain configs", "configs", resp) // Populate the map. for i := range resp.Selectors { From c6b8f8eaee54a0810e43ed2c152a9d499cc81c55 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Sun, 2 Feb 2025 22:31:04 +0400 Subject: [PATCH 03/35] v0 --- mocks/pkg/contractreader/extended.go | 57 +++++++++ pkg/contractreader/extended.go | 68 +++++++++++ pkg/reader/ccip.go | 176 +++++++++++++++++++++++++-- 3 files changed, 291 insertions(+), 10 deletions(-) diff --git a/mocks/pkg/contractreader/extended.go b/mocks/pkg/contractreader/extended.go index 2b748854c..8db3ec991 100644 --- a/mocks/pkg/contractreader/extended.go +++ b/mocks/pkg/contractreader/extended.go @@ -193,6 +193,63 @@ func (_c *MockExtended_ExtendedBatchGetLatestValues_Call) RunAndReturn(run func( return _c } +// ExtendedBatchGetLatestValuesGraceful provides a mock function with given fields: ctx, request +func (_m *MockExtended) ExtendedBatchGetLatestValuesGraceful(ctx context.Context, request contractreader.ExtendedBatchGetLatestValuesRequest) (contractreader.BatchGetLatestValuesGracefulResult, error) { + ret := _m.Called(ctx, request) + + if len(ret) == 0 { + panic("no return value specified for ExtendedBatchGetLatestValuesGraceful") + } + + var r0 contractreader.BatchGetLatestValuesGracefulResult + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, contractreader.ExtendedBatchGetLatestValuesRequest) (contractreader.BatchGetLatestValuesGracefulResult, error)); ok { + return rf(ctx, request) + } + if rf, ok := ret.Get(0).(func(context.Context, contractreader.ExtendedBatchGetLatestValuesRequest) contractreader.BatchGetLatestValuesGracefulResult); ok { + r0 = rf(ctx, request) + } else { + r0 = ret.Get(0).(contractreader.BatchGetLatestValuesGracefulResult) + } + + if rf, ok := ret.Get(1).(func(context.Context, contractreader.ExtendedBatchGetLatestValuesRequest) error); ok { + r1 = rf(ctx, request) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockExtended_ExtendedBatchGetLatestValuesGraceful_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ExtendedBatchGetLatestValuesGraceful' +type MockExtended_ExtendedBatchGetLatestValuesGraceful_Call struct { + *mock.Call +} + +// ExtendedBatchGetLatestValuesGraceful is a helper method to define mock.On call +// - ctx context.Context +// - request contractreader.ExtendedBatchGetLatestValuesRequest +func (_e *MockExtended_Expecter) ExtendedBatchGetLatestValuesGraceful(ctx interface{}, request interface{}) *MockExtended_ExtendedBatchGetLatestValuesGraceful_Call { + return &MockExtended_ExtendedBatchGetLatestValuesGraceful_Call{Call: _e.mock.On("ExtendedBatchGetLatestValuesGraceful", ctx, request)} +} + +func (_c *MockExtended_ExtendedBatchGetLatestValuesGraceful_Call) Run(run func(ctx context.Context, request contractreader.ExtendedBatchGetLatestValuesRequest)) *MockExtended_ExtendedBatchGetLatestValuesGraceful_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(contractreader.ExtendedBatchGetLatestValuesRequest)) + }) + return _c +} + +func (_c *MockExtended_ExtendedBatchGetLatestValuesGraceful_Call) Return(_a0 contractreader.BatchGetLatestValuesGracefulResult, _a1 error) *MockExtended_ExtendedBatchGetLatestValuesGraceful_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockExtended_ExtendedBatchGetLatestValuesGraceful_Call) RunAndReturn(run func(context.Context, contractreader.ExtendedBatchGetLatestValuesRequest) (contractreader.BatchGetLatestValuesGracefulResult, error)) *MockExtended_ExtendedBatchGetLatestValuesGraceful_Call { + _c.Call.Return(run) + return _c +} + // ExtendedGetLatestValue provides a mock function with given fields: ctx, contractName, methodName, confidenceLevel, params, returnVal func (_m *MockExtended) ExtendedGetLatestValue(ctx context.Context, contractName string, methodName string, confidenceLevel primitives.ConfidenceLevel, params interface{}, returnVal interface{}) error { ret := _m.Called(ctx, contractName, methodName, confidenceLevel, params, returnVal) diff --git a/pkg/contractreader/extended.go b/pkg/contractreader/extended.go index 0e9390a82..83ab24201 100644 --- a/pkg/contractreader/extended.go +++ b/pkg/contractreader/extended.go @@ -84,6 +84,16 @@ type Extended interface { ctx context.Context, request ExtendedBatchGetLatestValuesRequest, ) (types.BatchGetLatestValuesResult, error) + + // ExtendedBatchGetLatestValuesGraceful performs the same operations as ExtendedBatchGetLatestValues + // but handles ErrNoBindings gracefully by: + // 1. Skipping contracts with no bindings instead of returning an error + // 2. Returning partial results for contracts that do have bindings + // 3. Including information about which contracts were skipped due to no bindings + ExtendedBatchGetLatestValuesGraceful( + ctx context.Context, + request ExtendedBatchGetLatestValuesRequest, + ) (BatchGetLatestValuesGracefulResult, error) } type ExtendedBatchGetLatestValuesRequest map[string]types.ContractBatch @@ -102,6 +112,12 @@ type extendedContractReader struct { mu *sync.RWMutex } +// BatchGetLatestValuesGracefulResult is the result of ExtendedBatchGetLatestValuesGraceful. +type BatchGetLatestValuesGracefulResult struct { + Results types.BatchGetLatestValuesResult + SkippedNoBinds []string // List of contract names that were skipped due to no bindings +} + func NewExtendedContractReader(baseContractReader ContractReaderFacade) Extended { // avoid double wrapping if ecr, ok := baseContractReader.(Extended); ok { @@ -232,6 +248,58 @@ func (e *extendedContractReader) BatchGetLatestValues( return result, err } +// ExtendedBatchGetLatestValuesGraceful performs the same operations as ExtendedBatchGetLatestValues +// but handles ErrNoBindings gracefully by: +// 1. Skipping contracts with no bindings instead of returning an error +// 2. Returning partial results for contracts that do have bindings +// 3. Including information about which contracts were skipped due to no bindings + +func (e *extendedContractReader) ExtendedBatchGetLatestValuesGraceful( + ctx context.Context, + request ExtendedBatchGetLatestValuesRequest, +) (BatchGetLatestValuesGracefulResult, error) { + // Convert the request from contract names to BoundContracts + convertedRequest := make(types.BatchGetLatestValuesRequest) + var skippedContracts []string + + for contractName, batch := range request { + // Get the binding for this contract name + binding, err := e.getOneBinding(contractName) + if err != nil { + if errors.Is(err, ErrNoBindings) { + // Track skipped contracts but continue processing + skippedContracts = append(skippedContracts, contractName) + continue + } + // Return error for any other binding issues + return BatchGetLatestValuesGracefulResult{}, fmt.Errorf( + "BatchGetLatestValuesGraceful: failed to get binding for contract %s: %w", contractName, err) + } + + // Use the resolved binding for the request + convertedRequest[binding.Binding] = batch + } + + // If we have no valid bindings after filtering, return empty result + if len(convertedRequest) == 0 { + return BatchGetLatestValuesGracefulResult{ + Results: make(types.BatchGetLatestValuesResult), + SkippedNoBinds: skippedContracts, + }, nil + } + + // Call the underlying BatchGetLatestValues with the converted request + results, err := e.BatchGetLatestValues(ctx, convertedRequest) + if err != nil { + return BatchGetLatestValuesGracefulResult{}, err + } + + return BatchGetLatestValuesGracefulResult{ + Results: results, + SkippedNoBinds: skippedContracts, + }, nil +} + func (e *extendedContractReader) ExtendedBatchGetLatestValues( ctx context.Context, request ExtendedBatchGetLatestValuesRequest, diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 63140fa0e..dc7e2a668 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1230,25 +1230,19 @@ func (r *ccipChainReader) getAllOffRampSourceChainsConfig( configs := make(map[cciptypes.ChainSelector]sourceChainConfig) - var resp selectorsAndConfigs - err := r.contractReaders[chain].ExtendedGetLatestValue( - ctx, - consts.ContractNameOffRamp, - consts.MethodNameOffRampGetAllSourceChainConfigs, - primitives.Unconfirmed, - map[string]any{}, - &resp, - ) + call, err := r.refresh(ctx) if err != nil { return nil, fmt.Errorf("failed to get source chain configs for source chain %d: %w", chain, err) } + resp := call.SelectorsAndConf + if len(resp.SourceChainConfigs) != len(resp.Selectors) { return nil, fmt.Errorf("selectors and source chain configs length mismatch: %v", resp) } - lggr.Infow("got source chain configs", "configs", resp) + lggr.Infow("got source chain configs", "configs", resp, "chain", chain) // Populate the map. for i := range resp.Selectors { @@ -1774,3 +1768,165 @@ func validateSendRequestedEvent( // Interface compliance check var _ CCIPReader = (*ccipChainReader)(nil) + +// refresh fetches all configurations and updates the cache +func (r *ccipChainReader) refresh(ctx context.Context) (NogoResponse, error) { + requests := r.prepareBatchRequests() + + batchResult, err := r.contractReaders[r.destChain].ExtendedBatchGetLatestValuesGraceful(ctx, requests) + if err != nil { + return NogoResponse{}, fmt.Errorf("batch get latest values: %w", err) + } + // print the batchResult + for contract, results := range batchResult.Results { + r.lggr.Infow("contract is", "contract", contract) + for i, result := range results { + r.lggr.Infow("result is", "result", result) + val, err := result.GetResult() + if err != nil { + r.lggr.Errorw("get offramp result %d: %w", i, err) + } + r.lggr.Infow("val is", "val", val) + } + } + + r.lggr.Infow("batchResult.SkippedNoBinds is", "batchResult.SkippedNoBinds", batchResult.SkippedNoBinds) + // Log skipped contracts if any for debugging + // Clear skipped contract values from cache + if len(batchResult.SkippedNoBinds) > 0 { + r.lggr.Infow("some contracts were skipped due to no bindings", "contracts", batchResult.SkippedNoBinds) + // c.clearSkippedContractValues(batchResult.SkippedNoBinds) + } + + return r.updateFromResults(batchResult.Results) +} + +// prepareBatchRequests creates the batch request for all configurations +func (r *ccipChainReader) prepareBatchRequests() contractreader.ExtendedBatchGetLatestValuesRequest { + var ( + commitLatestOCRConfig OCRConfigResponse + execLatestOCRConfig OCRConfigResponse + staticConfig offRampStaticChainConfig + dynamicConfig offRampDynamicChainConfig + selectorsAndConf selectorsAndConfigs + ) + + return contractreader.ExtendedBatchGetLatestValuesRequest{ + consts.ContractNameOffRamp: { + { + ReadName: consts.MethodNameOffRampLatestConfigDetails, + Params: map[string]any{ + "ocrPluginType": consts.PluginTypeCommit, + }, + ReturnVal: &commitLatestOCRConfig, + }, + { + ReadName: consts.MethodNameOffRampLatestConfigDetails, + Params: map[string]any{ + "ocrPluginType": consts.PluginTypeExecute, + }, + ReturnVal: &execLatestOCRConfig, + }, + { + ReadName: consts.MethodNameOffRampGetStaticConfig, + Params: map[string]any{}, + ReturnVal: &staticConfig, + }, + { + ReadName: consts.MethodNameOffRampGetDynamicConfig, + Params: map[string]any{}, + ReturnVal: &dynamicConfig, + }, + { + ReadName: consts.MethodNameOffRampGetAllSourceChainConfigs, + Params: map[string]any{}, + ReturnVal: &selectorsAndConf, + }, + }, + } +} + +// updateFromResults updates the cache with results from the batch request +func (r *ccipChainReader) updateFromResults(batchResult types.BatchGetLatestValuesResult) (NogoResponse, error) { + for contract, results := range batchResult { + return r.handleContractResults(contract, results) + } + return NogoResponse{}, nil +} + +// handleContractResults processes results for a specific contract +func (r *ccipChainReader) handleContractResults(contract types.BoundContract, results []types.BatchReadResult) (NogoResponse, error) { + switch contract.Name { + case consts.ContractNameOffRamp: + r.lggr.Infow("In handleContractResults") + return r.handleOffRampResults(results) + } + return NogoResponse{}, fmt.Errorf("unexpected contract name %s", contract.Name) +} + +type NogoResponse struct { + CommitLatestOCRConfig OCRConfigResponse + ExecLatestOCRConfig OCRConfigResponse + StaticConfig offRampStaticChainConfig + DynamicConfig offRampDynamicChainConfig + SelectorsAndConf selectorsAndConfigs +} + +// handleOffRampResults processes offramp-specific results +func (r *ccipChainReader) handleOffRampResults(results []types.BatchReadResult) (NogoResponse, error) { + response := NogoResponse{} + + for i, result := range results { + val, err := result.GetResult() + if err != nil { + return NogoResponse{}, fmt.Errorf("get offramp result %d: %w", i, err) + } + r.lggr.Infow("val is", "val", val) + + switch i { + case 0: + if typed, ok := val.(*OCRConfigResponse); ok { + r.lggr.Infow("typed is", "typed", typed) + response.CommitLatestOCRConfig = *typed + } + case 1: + if typed, ok := val.(*OCRConfigResponse); ok { + r.lggr.Infow("typed is", "typed", typed) + response.ExecLatestOCRConfig = *typed + } + case 2: + if typed, ok := val.(*offRampStaticChainConfig); ok { + r.lggr.Infow("typed is", "typed", typed) + response.StaticConfig = *typed + } + case 3: + if typed, ok := val.(*offRampDynamicChainConfig); ok { + r.lggr.Infow("typed is", "typed", typed) + response.DynamicConfig = *typed + } + case 4: + if typed, ok := val.(*selectorsAndConfigs); ok { + r.lggr.Infow("typed is", "typed", typed) + response.SelectorsAndConf = *typed + } + } + } + return response, nil +} + +type OCRConfigResponse struct { + OCRConfig OCRConfig +} + +type OCRConfig struct { + ConfigInfo ConfigInfo + Signers [][]byte + Transmitters [][]byte +} + +type ConfigInfo struct { + ConfigDigest [32]byte + F uint8 + N uint8 + IsSignatureVerificationEnabled bool +} From 28dd06a6127ea2b49ef7aac5a6f49d80efb4d12e Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Sun, 2 Feb 2025 22:37:31 +0400 Subject: [PATCH 04/35] lint --- pkg/reader/ccip.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index dc7e2a668..30f84835f 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1855,7 +1855,8 @@ func (r *ccipChainReader) updateFromResults(batchResult types.BatchGetLatestValu } // handleContractResults processes results for a specific contract -func (r *ccipChainReader) handleContractResults(contract types.BoundContract, results []types.BatchReadResult) (NogoResponse, error) { +func (r *ccipChainReader) handleContractResults( + contract types.BoundContract, results []types.BatchReadResult) (NogoResponse, error) { switch contract.Name { case consts.ContractNameOffRamp: r.lggr.Infow("In handleContractResults") From d8b98fbb95f450186b4ec286b0b39c2b09d3caf3 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Sun, 2 Feb 2025 23:18:59 +0400 Subject: [PATCH 05/35] rmn proxy --- pkg/reader/ccip.go | 69 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 30f84835f..602c814c1 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1236,7 +1236,7 @@ func (r *ccipChainReader) getAllOffRampSourceChainsConfig( chain, err) } - resp := call.SelectorsAndConf + resp := call.Offramp.SelectorsAndConf if len(resp.SourceChainConfigs) != len(resp.Selectors) { return nil, fmt.Errorf("selectors and source chain configs length mismatch: %v", resp) @@ -1488,16 +1488,8 @@ func (r *ccipChainReader) getRMNRemoteAddress( if err != nil { return nil, fmt.Errorf("bind RMN proxy contract: %w", err) } - - // get the RMN remote address from the proxy - var rmnRemoteAddress []byte - err = r.getDestinationData( - ctx, - chain, - consts.ContractNameRMNProxy, - consts.MethodNameGetARM, - &rmnRemoteAddress, - ) + response, err := r.refresh(ctx) + rmnRemoteAddress := response.RMNProxy.RMNRemoteAddress if err != nil { return nil, fmt.Errorf("unable to lookup RMN remote address (RMN proxy): %w", err) } @@ -1809,6 +1801,7 @@ func (r *ccipChainReader) prepareBatchRequests() contractreader.ExtendedBatchGet staticConfig offRampStaticChainConfig dynamicConfig offRampDynamicChainConfig selectorsAndConf selectorsAndConfigs + rmnRemoteAddress []byte ) return contractreader.ExtendedBatchGetLatestValuesRequest{ @@ -1843,6 +1836,11 @@ func (r *ccipChainReader) prepareBatchRequests() contractreader.ExtendedBatchGet ReturnVal: &selectorsAndConf, }, }, + consts.ContractNameRMNProxy: {{ + ReadName: consts.MethodNameGetARM, + Params: map[string]any{}, + ReturnVal: &rmnRemoteAddress, + }}, } } @@ -1857,15 +1855,50 @@ func (r *ccipChainReader) updateFromResults(batchResult types.BatchGetLatestValu // handleContractResults processes results for a specific contract func (r *ccipChainReader) handleContractResults( contract types.BoundContract, results []types.BatchReadResult) (NogoResponse, error) { + offramp := OfframpNogoResponse{} + rmnProxy := RMNProxyNogoResponse{} + + var err error switch contract.Name { case consts.ContractNameOffRamp: r.lggr.Infow("In handleContractResults") - return r.handleOffRampResults(results) + offramp, err = r.handleOffRampResults(results) + if err != nil { + return NogoResponse{}, fmt.Errorf("handle offramp results: %w", err) + } + case consts.ContractNameRMNProxy: + rmnProxy, err = r.handleRMNProxyResults(results) + if err != nil { + return NogoResponse{}, fmt.Errorf("handle router results: %w", err) + } + } + return NogoResponse{ + Offramp: offramp, + RMNProxy: rmnProxy, + }, nil +} + +func (r *ccipChainReader) handleRMNProxyResults(results []types.BatchReadResult) (RMNProxyNogoResponse, error) { + rmnProxy := RMNProxyNogoResponse{} + + if len(results) > 0 { + val, err := results[0].GetResult() + if err != nil { + return RMNProxyNogoResponse{}, fmt.Errorf("get RMN proxy result: %w", err) + } + if typed, ok := val.(*cciptypes.Bytes); ok { + rmnProxy.RMNRemoteAddress = *typed + } } - return NogoResponse{}, fmt.Errorf("unexpected contract name %s", contract.Name) + return rmnProxy, nil } type NogoResponse struct { + Offramp OfframpNogoResponse + RMNProxy RMNProxyNogoResponse +} + +type OfframpNogoResponse struct { CommitLatestOCRConfig OCRConfigResponse ExecLatestOCRConfig OCRConfigResponse StaticConfig offRampStaticChainConfig @@ -1873,14 +1906,18 @@ type NogoResponse struct { SelectorsAndConf selectorsAndConfigs } +type RMNProxyNogoResponse struct { + RMNRemoteAddress cciptypes.Bytes +} + // handleOffRampResults processes offramp-specific results -func (r *ccipChainReader) handleOffRampResults(results []types.BatchReadResult) (NogoResponse, error) { - response := NogoResponse{} +func (r *ccipChainReader) handleOffRampResults(results []types.BatchReadResult) (OfframpNogoResponse, error) { + response := OfframpNogoResponse{} for i, result := range results { val, err := result.GetResult() if err != nil { - return NogoResponse{}, fmt.Errorf("get offramp result %d: %w", i, err) + return OfframpNogoResponse{}, fmt.Errorf("get offramp result %d: %w", i, err) } r.lggr.Infow("val is", "val", val) From e45482b79dc86821ae42d4ebe1a1aa1ec2939908 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Sun, 2 Feb 2025 23:47:12 +0400 Subject: [PATCH 06/35] log rmnremote addy --- pkg/reader/ccip.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 602c814c1..964fdb23a 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -731,7 +731,7 @@ func (r *ccipChainReader) GetRMNRemoteConfig( if err != nil { return rmntypes.RemoteConfig{}, fmt.Errorf("get RMNRemote address: %w", err) } - lggr.Debugw("got RMNRemote address", "address", rmnRemoteAddress) + lggr.Infow("got RMNRemote address", "address", rmnRemoteAddress) // TODO: make the calls in parallel using errgroup var vc versionedConfig From cb4b561028efd8a6d7bbc821f759d63342c4ae3e Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 00:13:12 +0400 Subject: [PATCH 07/35] log both --- pkg/reader/ccip.go | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 964fdb23a..a1428b808 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1488,13 +1488,29 @@ func (r *ccipChainReader) getRMNRemoteAddress( if err != nil { return nil, fmt.Errorf("bind RMN proxy contract: %w", err) } + + // get the RMN remote address from the proxy + var rmnRemoteAddressFromNormalCall []byte + err = r.getDestinationData( + ctx, + chain, + consts.ContractNameRMNProxy, + consts.MethodNameGetARM, + &rmnRemoteAddressFromNormalCall, + ) + if err != nil { + return nil, fmt.Errorf("unable to lookup RMN remote address (RMN proxy): %w", err) + } + response, err := r.refresh(ctx) - rmnRemoteAddress := response.RMNProxy.RMNRemoteAddress + rmnRemoteAddressFromBatch := response.RMNProxy.RMNRemoteAddress + + r.lggr.Infow("got RMN remote address", "rmnRemoteAddressFromNormalCall", rmnRemoteAddressFromNormalCall, "rmnRemoteAddressFromBatch", rmnRemoteAddressFromBatch) if err != nil { return nil, fmt.Errorf("unable to lookup RMN remote address (RMN proxy): %w", err) } - return rmnRemoteAddress, nil + return rmnRemoteAddressFromNormalCall, nil } // Get the DestChainConfig from the FeeQuoter contract on the given chain. From ba5faf201f14bf55ae0aefd6269d6a80f90ac856 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 00:28:15 +0400 Subject: [PATCH 08/35] more logging --- pkg/reader/ccip.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index a1428b808..17da89751 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1877,12 +1877,13 @@ func (r *ccipChainReader) handleContractResults( var err error switch contract.Name { case consts.ContractNameOffRamp: - r.lggr.Infow("In handleContractResults") + r.lggr.Infow("In handleContractResults ContractNameOffRamp") offramp, err = r.handleOffRampResults(results) if err != nil { return NogoResponse{}, fmt.Errorf("handle offramp results: %w", err) } case consts.ContractNameRMNProxy: + r.lggr.Infow("In handleContractResults ContractNameRMNProxy") rmnProxy, err = r.handleRMNProxyResults(results) if err != nil { return NogoResponse{}, fmt.Errorf("handle router results: %w", err) @@ -1897,12 +1898,16 @@ func (r *ccipChainReader) handleContractResults( func (r *ccipChainReader) handleRMNProxyResults(results []types.BatchReadResult) (RMNProxyNogoResponse, error) { rmnProxy := RMNProxyNogoResponse{} + r.lggr.Infow("results is", "results", results) + if len(results) > 0 { val, err := results[0].GetResult() + r.lggr.Infow("val is", "val", val) if err != nil { return RMNProxyNogoResponse{}, fmt.Errorf("get RMN proxy result: %w", err) } if typed, ok := val.(*cciptypes.Bytes); ok { + r.lggr.Infow("typed is", "typed", typed) rmnProxy.RMNRemoteAddress = *typed } } From 5c5e16652042b3f5c51f31c7d3ea55d9184ec90b Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 00:37:50 +0400 Subject: [PATCH 09/35] better logs --- pkg/reader/ccip.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 17da89751..55d0082c8 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1898,19 +1898,22 @@ func (r *ccipChainReader) handleContractResults( func (r *ccipChainReader) handleRMNProxyResults(results []types.BatchReadResult) (RMNProxyNogoResponse, error) { rmnProxy := RMNProxyNogoResponse{} - r.lggr.Infow("results is", "results", results) + r.lggr.Infow("handleRMNProxyResults - results is", "results", results) if len(results) > 0 { val, err := results[0].GetResult() - r.lggr.Infow("val is", "val", val) + r.lggr.Infow("handleRMNProxyResults- val is", "val", val) if err != nil { return RMNProxyNogoResponse{}, fmt.Errorf("get RMN proxy result: %w", err) } if typed, ok := val.(*cciptypes.Bytes); ok { - r.lggr.Infow("typed is", "typed", typed) + r.lggr.Infow("handleRMNProxyResults - typed is", "typed", typed) rmnProxy.RMNRemoteAddress = *typed + } else { + r.lggr.Infow("handleRMNProxyResults - val is not of type Bytes", "val", val) } } + r.lggr.Infow("handleRMNProxyResults - rmnProxy is", "rmnProxy", rmnProxy) return rmnProxy, nil } From 16f7f7a29b7c8de385364b2763d99a9b108d5cfc Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 00:42:03 +0400 Subject: [PATCH 10/35] change type of reflection --- pkg/reader/ccip.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 55d0082c8..bc852be28 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1902,11 +1902,11 @@ func (r *ccipChainReader) handleRMNProxyResults(results []types.BatchReadResult) if len(results) > 0 { val, err := results[0].GetResult() - r.lggr.Infow("handleRMNProxyResults- val is", "val", val) + r.lggr.Infow("handleRMNProxyResults - val is", "val", val) if err != nil { return RMNProxyNogoResponse{}, fmt.Errorf("get RMN proxy result: %w", err) } - if typed, ok := val.(*cciptypes.Bytes); ok { + if typed, ok := val.(*[]byte); ok { r.lggr.Infow("handleRMNProxyResults - typed is", "typed", typed) rmnProxy.RMNRemoteAddress = *typed } else { From c1eec5c2c4caecd059a9d1b302f75de96395dee9 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 00:49:24 +0400 Subject: [PATCH 11/35] use type --- pkg/reader/ccip.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index bc852be28..847a926da 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1510,7 +1510,7 @@ func (r *ccipChainReader) getRMNRemoteAddress( return nil, fmt.Errorf("unable to lookup RMN remote address (RMN proxy): %w", err) } - return rmnRemoteAddressFromNormalCall, nil + return rmnRemoteAddressFromBatch, nil } // Get the DestChainConfig from the FeeQuoter contract on the given chain. From 1c5ddff605e602af031dec27ea5d78d154e029c1 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 01:01:16 +0400 Subject: [PATCH 12/35] change to []byte --- pkg/reader/ccip.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 847a926da..cb26106af 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1931,7 +1931,7 @@ type OfframpNogoResponse struct { } type RMNProxyNogoResponse struct { - RMNRemoteAddress cciptypes.Bytes + RMNRemoteAddress []byte } // handleOffRampResults processes offramp-specific results From 88eede60f3c1999425e64bd6150eba3cad58a54d Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 11:50:52 +0400 Subject: [PATCH 13/35] looogs --- pkg/reader/ccip.go | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index cb26106af..1410e2e49 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1503,12 +1503,12 @@ func (r *ccipChainReader) getRMNRemoteAddress( } response, err := r.refresh(ctx) - rmnRemoteAddressFromBatch := response.RMNProxy.RMNRemoteAddress - - r.lggr.Infow("got RMN remote address", "rmnRemoteAddressFromNormalCall", rmnRemoteAddressFromNormalCall, "rmnRemoteAddressFromBatch", rmnRemoteAddressFromBatch) if err != nil { return nil, fmt.Errorf("unable to lookup RMN remote address (RMN proxy): %w", err) } + rmnRemoteAddressFromBatch := response.RMNProxy.RMNRemoteAddress + + r.lggr.Infow("got RMN remote address", "rmnRemoteAddressFromNormalCall", rmnRemoteAddressFromNormalCall, "rmnRemoteAddressFromBatch", rmnRemoteAddressFromBatch) return rmnRemoteAddressFromBatch, nil } @@ -1889,6 +1889,8 @@ func (r *ccipChainReader) handleContractResults( return NogoResponse{}, fmt.Errorf("handle router results: %w", err) } } + + r.lggr.Infow("In handleContractResults - offramp is", "rmnProxy", rmnProxy, "offramp", offramp) return NogoResponse{ Offramp: offramp, RMNProxy: rmnProxy, @@ -1943,32 +1945,25 @@ func (r *ccipChainReader) handleOffRampResults(results []types.BatchReadResult) if err != nil { return OfframpNogoResponse{}, fmt.Errorf("get offramp result %d: %w", i, err) } - r.lggr.Infow("val is", "val", val) - switch i { case 0: if typed, ok := val.(*OCRConfigResponse); ok { - r.lggr.Infow("typed is", "typed", typed) response.CommitLatestOCRConfig = *typed } case 1: if typed, ok := val.(*OCRConfigResponse); ok { - r.lggr.Infow("typed is", "typed", typed) response.ExecLatestOCRConfig = *typed } case 2: if typed, ok := val.(*offRampStaticChainConfig); ok { - r.lggr.Infow("typed is", "typed", typed) response.StaticConfig = *typed } case 3: if typed, ok := val.(*offRampDynamicChainConfig); ok { - r.lggr.Infow("typed is", "typed", typed) response.DynamicConfig = *typed } case 4: if typed, ok := val.(*selectorsAndConfigs); ok { - r.lggr.Infow("typed is", "typed", typed) response.SelectorsAndConf = *typed } } From 3ce66591fce47e4f5488cc0c095d31639c0f6068 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 13:01:18 +0400 Subject: [PATCH 14/35] add log on contract name --- pkg/reader/ccip.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 1410e2e49..071cf430d 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -724,7 +724,7 @@ func (r *ccipChainReader) GetRMNRemoteConfig( // Here we will get the RMNRemote address from the proxy contract by calling the RMNProxy contract. proxyContractAddress, err := r.GetContractAddress(consts.ContractNameRMNRemote, r.destChain) if err != nil { - return rmntypes.RemoteConfig{}, fmt.Errorf("get RMNRemote proxy contract address: %w", err) + return rmntypes.RemoteConfig{}, fmt.Errorf("GetRMNRemoteConfigGetRMNRemoteConfig: %w", err) } rmnRemoteAddress, err := r.getRMNRemoteAddress(ctx, lggr, r.destChain, proxyContractAddress) @@ -1874,6 +1874,8 @@ func (r *ccipChainReader) handleContractResults( offramp := OfframpNogoResponse{} rmnProxy := RMNProxyNogoResponse{} + r.lggr.Infow("In handleContractResults - contract is", "contract", contract) + var err error switch contract.Name { case consts.ContractNameOffRamp: @@ -1886,7 +1888,7 @@ func (r *ccipChainReader) handleContractResults( r.lggr.Infow("In handleContractResults ContractNameRMNProxy") rmnProxy, err = r.handleRMNProxyResults(results) if err != nil { - return NogoResponse{}, fmt.Errorf("handle router results: %w", err) + return NogoResponse{}, fmt.Errorf("handle RMN proxy results: %w", err) } } From 09f1ba6500fe38e13dd05430e97ba6186a302e44 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 13:11:38 +0400 Subject: [PATCH 15/35] using reflect --- pkg/reader/ccip.go | 64 +++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 071cf430d..9dea37eeb 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "math/big" + "reflect" "sort" "strconv" "sync" @@ -1860,43 +1861,54 @@ func (r *ccipChainReader) prepareBatchRequests() contractreader.ExtendedBatchGet } } +// ContractHandler defines how to handle different contract results +type ContractHandler struct { + handler func([]types.BatchReadResult) (interface{}, error) + resultType reflect.Type +} + // updateFromResults updates the cache with results from the batch request func (r *ccipChainReader) updateFromResults(batchResult types.BatchGetLatestValuesResult) (NogoResponse, error) { - for contract, results := range batchResult { - return r.handleContractResults(contract, results) + handlers := map[string]ContractHandler{ + consts.ContractNameOffRamp: { + handler: func(results []types.BatchReadResult) (interface{}, error) { + return r.handleOffRampResults(results) + }, + resultType: reflect.TypeOf(OfframpNogoResponse{}), + }, + consts.ContractNameRMNProxy: { + handler: func(results []types.BatchReadResult) (interface{}, error) { + return r.handleRMNProxyResults(results) + }, + resultType: reflect.TypeOf(RMNProxyNogoResponse{}), + }, } - return NogoResponse{}, nil -} -// handleContractResults processes results for a specific contract -func (r *ccipChainReader) handleContractResults( - contract types.BoundContract, results []types.BatchReadResult) (NogoResponse, error) { - offramp := OfframpNogoResponse{} - rmnProxy := RMNProxyNogoResponse{} + response := NogoResponse{} - r.lggr.Infow("In handleContractResults - contract is", "contract", contract) + for contract, results := range batchResult { + r.lggr.Infow("Processing contract results", "contract", contract.Name) - var err error - switch contract.Name { - case consts.ContractNameOffRamp: - r.lggr.Infow("In handleContractResults ContractNameOffRamp") - offramp, err = r.handleOffRampResults(results) - if err != nil { - return NogoResponse{}, fmt.Errorf("handle offramp results: %w", err) + handler, exists := handlers[contract.Name] + if !exists { + r.lggr.Warnw("No handler found for contract", "contract", contract.Name) + continue } - case consts.ContractNameRMNProxy: - r.lggr.Infow("In handleContractResults ContractNameRMNProxy") - rmnProxy, err = r.handleRMNProxyResults(results) + + result, err := handler.handler(results) if err != nil { - return NogoResponse{}, fmt.Errorf("handle RMN proxy results: %w", err) + return NogoResponse{}, fmt.Errorf("handle %s results: %w", contract.Name, err) + } + + // Set the result in the appropriate field using reflection + responseValue := reflect.ValueOf(&response).Elem() + field := responseValue.FieldByName(contract.Name) + if field.IsValid() && field.Type() == handler.resultType { + field.Set(reflect.ValueOf(result)) } } - r.lggr.Infow("In handleContractResults - offramp is", "rmnProxy", rmnProxy, "offramp", offramp) - return NogoResponse{ - Offramp: offramp, - RMNProxy: rmnProxy, - }, nil + return response, nil } func (r *ccipChainReader) handleRMNProxyResults(results []types.BatchReadResult) (RMNProxyNogoResponse, error) { From a5caa296fea3cc5a47bad7e4e360299b9d79d630 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 13:25:50 +0400 Subject: [PATCH 16/35] rmnRemoteAddressFromNormalCall --- pkg/reader/ccip.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 9dea37eeb..d96ebc4cd 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1511,7 +1511,7 @@ func (r *ccipChainReader) getRMNRemoteAddress( r.lggr.Infow("got RMN remote address", "rmnRemoteAddressFromNormalCall", rmnRemoteAddressFromNormalCall, "rmnRemoteAddressFromBatch", rmnRemoteAddressFromBatch) - return rmnRemoteAddressFromBatch, nil + return rmnRemoteAddressFromNormalCall, nil } // Get the DestChainConfig from the FeeQuoter contract on the given chain. From 566f732ca7781473f9fec96fd8c27cad5dda4a3d Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 13:50:26 +0400 Subject: [PATCH 17/35] check --- pkg/reader/ccip.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index d96ebc4cd..6440e86cb 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1900,6 +1900,8 @@ func (r *ccipChainReader) updateFromResults(batchResult types.BatchGetLatestValu return NogoResponse{}, fmt.Errorf("handle %s results: %w", contract.Name, err) } + r.lggr.Infow("Result is", "result", result) + // Set the result in the appropriate field using reflection responseValue := reflect.ValueOf(&response).Elem() field := responseValue.FieldByName(contract.Name) @@ -1908,6 +1910,8 @@ func (r *ccipChainReader) updateFromResults(batchResult types.BatchGetLatestValu } } + r.lggr.Infow("Response is", "response", response) + return response, nil } From 3997271e5b2897ad3473d4272784af090305e37d Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 14:07:51 +0400 Subject: [PATCH 18/35] fix updateFromResults --- pkg/reader/ccip.go | 57 ++++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 40 deletions(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 6440e86cb..f704e9b70 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "math/big" - "reflect" "sort" "strconv" "sync" @@ -1861,57 +1860,35 @@ func (r *ccipChainReader) prepareBatchRequests() contractreader.ExtendedBatchGet } } -// ContractHandler defines how to handle different contract results -type ContractHandler struct { - handler func([]types.BatchReadResult) (interface{}, error) - resultType reflect.Type -} - -// updateFromResults updates the cache with results from the batch request func (r *ccipChainReader) updateFromResults(batchResult types.BatchGetLatestValuesResult) (NogoResponse, error) { - handlers := map[string]ContractHandler{ - consts.ContractNameOffRamp: { - handler: func(results []types.BatchReadResult) (interface{}, error) { - return r.handleOffRampResults(results) - }, - resultType: reflect.TypeOf(OfframpNogoResponse{}), - }, - consts.ContractNameRMNProxy: { - handler: func(results []types.BatchReadResult) (interface{}, error) { - return r.handleRMNProxyResults(results) - }, - resultType: reflect.TypeOf(RMNProxyNogoResponse{}), - }, - } - response := NogoResponse{} for contract, results := range batchResult { r.lggr.Infow("Processing contract results", "contract", contract.Name) - handler, exists := handlers[contract.Name] - if !exists { - r.lggr.Warnw("No handler found for contract", "contract", contract.Name) - continue - } - - result, err := handler.handler(results) - if err != nil { - return NogoResponse{}, fmt.Errorf("handle %s results: %w", contract.Name, err) - } + switch contract.Name { + case consts.ContractNameOffRamp: + offramp, err := r.handleOffRampResults(results) + if err != nil { + return NogoResponse{}, fmt.Errorf("handle offramp results: %w", err) + } + r.lggr.Infow("Result is", "result", offramp) + response.Offramp = offramp - r.lggr.Infow("Result is", "result", result) + case consts.ContractNameRMNProxy: + rmnProxy, err := r.handleRMNProxyResults(results) + if err != nil { + return NogoResponse{}, fmt.Errorf("handle RMN proxy results: %w", err) + } + r.lggr.Infow("Result is", "result", rmnProxy) + response.RMNProxy = rmnProxy - // Set the result in the appropriate field using reflection - responseValue := reflect.ValueOf(&response).Elem() - field := responseValue.FieldByName(contract.Name) - if field.IsValid() && field.Type() == handler.resultType { - field.Set(reflect.ValueOf(result)) + default: + r.lggr.Warnw("No handler found for contract", "contract", contract.Name) } } r.lggr.Infow("Response is", "response", response) - return response, nil } From efd984eae46200e9dc519a8c940f435575eb0cb5 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 14:22:06 +0400 Subject: [PATCH 19/35] rmnRemoteAddressFromBatch --- pkg/reader/ccip.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index f704e9b70..10265e406 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1510,7 +1510,7 @@ func (r *ccipChainReader) getRMNRemoteAddress( r.lggr.Infow("got RMN remote address", "rmnRemoteAddressFromNormalCall", rmnRemoteAddressFromNormalCall, "rmnRemoteAddressFromBatch", rmnRemoteAddressFromBatch) - return rmnRemoteAddressFromNormalCall, nil + return rmnRemoteAddressFromBatch, nil } // Get the DestChainConfig from the FeeQuoter contract on the given chain. From 6a62921c777281bf46f87a1b862f8b6d750f24ea Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 15:34:29 +0400 Subject: [PATCH 20/35] commitLatestOCRConfig --- pkg/reader/ccip.go | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 10265e406..2cb1b0d5e 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1640,7 +1640,16 @@ func (r *ccipChainReader) GetOffRampConfigDigest(ctx context.Context, pluginType return [32]byte{}, fmt.Errorf("get latest config digest: %w", err) } - return resp.OCRConfig.ConfigInfo.ConfigDigest, nil + result, err := r.refresh(ctx) + if err != nil { + return [32]byte{}, fmt.Errorf("get latest config digest: %w", err) + } + + respFromBatch := result.Offramp.CommitLatestOCRConfig + + r.lggr.Infow("got offramp config digest", "resp", resp, "respFromBatch", respFromBatch) + + return respFromBatch.OCRConfig.ConfigInfo.ConfigDigest, nil } func validateCommitReportAcceptedEvent(seq types.Sequence, gteTimestamp time.Time) (*CommitReportAcceptedEvent, error) { @@ -1809,6 +1818,10 @@ func (r *ccipChainReader) refresh(ctx context.Context) (NogoResponse, error) { return r.updateFromResults(batchResult.Results) } +// type rmnDigestHeader struct { +// DigestHeader cciptypes.Bytes32 +// } + // prepareBatchRequests creates the batch request for all configurations func (r *ccipChainReader) prepareBatchRequests() contractreader.ExtendedBatchGetLatestValuesRequest { var ( @@ -1818,6 +1831,9 @@ func (r *ccipChainReader) prepareBatchRequests() contractreader.ExtendedBatchGet dynamicConfig offRampDynamicChainConfig selectorsAndConf selectorsAndConfigs rmnRemoteAddress []byte + // rmnDigestHeader rmnDigestHeader + // rmnVersionConfig versionedConfig + // feeQuoterConfig feeQuoterStaticConfig ) return contractreader.ExtendedBatchGetLatestValuesRequest{ @@ -1857,6 +1873,23 @@ func (r *ccipChainReader) prepareBatchRequests() contractreader.ExtendedBatchGet Params: map[string]any{}, ReturnVal: &rmnRemoteAddress, }}, + // consts.ContractNameRMNRemote: { + // { + // ReadName: consts.MethodNameGetReportDigestHeader, + // Params: map[string]any{}, + // ReturnVal: &rmnDigestHeader, + // }, + // { + // ReadName: consts.MethodNameGetVersionedConfig, + // Params: map[string]any{}, + // ReturnVal: &rmnVersionConfig, + // }, + // }, + // consts.ContractNameFeeQuoter: {{ + // ReadName: consts.MethodNameFeeQuoterGetStaticConfig, + // Params: map[string]any{}, + // ReturnVal: &feeQuoterConfig, + // }}, } } From 2079135e97a0eac82ec680df3ef02866719bcaff Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 15:55:30 +0400 Subject: [PATCH 21/35] fix --- pkg/reader/ccip.go | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 2cb1b0d5e..76b05cf0d 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1608,23 +1608,6 @@ func (r *ccipChainReader) GetOffRampConfigDigest(ctx context.Context, pluginType return [32]byte{}, fmt.Errorf("validate dest=%d extended reader existence: %w", r.destChain, err) } - type ConfigInfo struct { - ConfigDigest [32]byte - F uint8 - N uint8 - IsSignatureVerificationEnabled bool - } - - type OCRConfig struct { - ConfigInfo ConfigInfo - Signers [][]byte - Transmitters [][]byte - } - - type OCRConfigResponse struct { - OCRConfig OCRConfig - } - var resp OCRConfigResponse err := r.contractReaders[r.destChain].ExtendedGetLatestValue( ctx, @@ -1645,7 +1628,12 @@ func (r *ccipChainReader) GetOffRampConfigDigest(ctx context.Context, pluginType return [32]byte{}, fmt.Errorf("get latest config digest: %w", err) } - respFromBatch := result.Offramp.CommitLatestOCRConfig + var respFromBatch OCRConfigResponse + if pluginType == consts.PluginTypeCommit { + respFromBatch = result.Offramp.CommitLatestOCRConfig + } else { + respFromBatch = result.Offramp.ExecLatestOCRConfig + } r.lggr.Infow("got offramp config digest", "resp", resp, "respFromBatch", respFromBatch) From c0bd25de8ebf23ec45b27648ed8a9b94ae0011ff Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 17:08:57 +0400 Subject: [PATCH 22/35] use all offramp --- pkg/reader/ccip.go | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 76b05cf0d..4bc72bc34 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -901,11 +901,18 @@ func (r *ccipChainReader) discoverOffRampContracts( return nil, fmt.Errorf("unable to lookup nonce manager and rmn proxy remote (offramp static config): %w", err) } - lggr.Infow("got offramp static config", "staticConfig", staticConfig) + respBatch, err := r.refresh(ctx) + if err != nil { + return nil, fmt.Errorf("refresh: %w", err) + } + + staticConfigBatch := respBatch.Offramp.StaticConfig + + lggr.Infow("got offramp static config", "staticConfig", staticConfig, "staticConfigBatch", staticConfigBatch) - resp = resp.Append(consts.ContractNameNonceManager, chain, staticConfig.NonceManager) - resp = resp.Append(consts.ContractNameRMNRemote, chain, staticConfig.RmnRemote) - lggr.Infow("appending RMN remote contract address", "address", staticConfig.RmnRemote) + resp = resp.Append(consts.ContractNameNonceManager, chain, staticConfigBatch.NonceManager) + resp = resp.Append(consts.ContractNameRMNRemote, chain, staticConfigBatch.RmnRemote) + lggr.Infow("appending RMN remote contract address", "address", staticConfigBatch.RmnRemote) } // FeeQuoter from the offRamp dynamic config. @@ -922,10 +929,17 @@ func (r *ccipChainReader) discoverOffRampContracts( return nil, fmt.Errorf("unable to lookup fee quoter (offramp dynamic config): %w", err) } - lggr.Infow("got offramp dynamic config", "dynamicConfig", dynamicConfig) + respBatch, err := r.refresh(ctx) + if err != nil { + return nil, fmt.Errorf("refresh: %w", err) + } + + dynamicConfigBatch := respBatch.Offramp.DynamicConfig + + lggr.Infow("got offramp dynamic config", "dynamicConfig", dynamicConfig, "dynamicConfigBatch", dynamicConfigBatch) - resp = resp.Append(consts.ContractNameFeeQuoter, chain, dynamicConfig.FeeQuoter) - lggr.Infow("appending fee quoter contract address", "address", dynamicConfig.FeeQuoter) + resp = resp.Append(consts.ContractNameFeeQuoter, chain, dynamicConfigBatch.FeeQuoter) + lggr.Infow("appending fee quoter contract address", "address", dynamicConfigBatch.FeeQuoter) } return resp, nil From 10a7431a1325800c101dd49fcfc6e5779905e768 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 17:36:56 +0400 Subject: [PATCH 23/35] rmnRemote --- pkg/reader/ccip.go | 145 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 109 insertions(+), 36 deletions(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 4bc72bc34..3b2293810 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -733,6 +733,11 @@ func (r *ccipChainReader) GetRMNRemoteConfig( } lggr.Infow("got RMNRemote address", "address", rmnRemoteAddress) + resultBatch, err := r.refresh(ctx) + if err != nil { + return rmntypes.RemoteConfig{}, fmt.Errorf("refresh: %w", err) + } + // TODO: make the calls in parallel using errgroup var vc versionedConfig err = r.contractReaders[r.destChain].ExtendedGetLatestValue( @@ -747,10 +752,14 @@ func (r *ccipChainReader) GetRMNRemoteConfig( return rmntypes.RemoteConfig{}, fmt.Errorf("get RMNRemote config: %w", err) } - type ret struct { - DigestHeader cciptypes.Bytes32 - } - var header ret + vcBatch := resultBatch.RMNRemote.RMNRemoteVersionedConfig + + lggr.Infow("got RMNRemote versioned config", "config", vc.Config, "batchConfig", vcBatch) + + // type ret struct { + // DigestHeader cciptypes.Bytes32 + // } + var header rmnDigestHeader err = r.contractReaders[r.destChain].ExtendedGetLatestValue( ctx, @@ -763,10 +772,12 @@ func (r *ccipChainReader) GetRMNRemoteConfig( if err != nil { return rmntypes.RemoteConfig{}, fmt.Errorf("get RMNRemote report digest header: %w", err) } - lggr.Infow("got RMNRemote report digest header", "digest", header.DigestHeader) - signers := make([]rmntypes.RemoteSignerInfo, 0, len(vc.Config.Signers)) - for _, signer := range vc.Config.Signers { + digestHeaderBatch := resultBatch.RMNRemote.RMNRemoteDigestHeader.DigestHeader + lggr.Infow("got RMNRemote report digest header", "digest", header.DigestHeader, "batchDigest", digestHeaderBatch) + + signers := make([]rmntypes.RemoteSignerInfo, 0, len(vcBatch.Config.Signers)) + for _, signer := range vcBatch.Config.Signers { signers = append(signers, rmntypes.RemoteSignerInfo{ OnchainPublicKey: signer.OnchainPublicKey, NodeIndex: signer.NodeIndex, @@ -775,11 +786,11 @@ func (r *ccipChainReader) GetRMNRemoteConfig( return rmntypes.RemoteConfig{ ContractAddress: rmnRemoteAddress, - ConfigDigest: vc.Config.RMNHomeContractConfigDigest, + ConfigDigest: vcBatch.Config.RMNHomeContractConfigDigest, Signers: signers, - FSign: vc.Config.F, - ConfigVersion: vc.Version, - RmnReportVersion: header.DigestHeader, + FSign: vcBatch.Config.F, + ConfigVersion: vcBatch.Version, + RmnReportVersion: digestHeaderBatch, }, nil } @@ -1820,9 +1831,9 @@ func (r *ccipChainReader) refresh(ctx context.Context) (NogoResponse, error) { return r.updateFromResults(batchResult.Results) } -// type rmnDigestHeader struct { -// DigestHeader cciptypes.Bytes32 -// } +type rmnDigestHeader struct { + DigestHeader cciptypes.Bytes32 +} // prepareBatchRequests creates the batch request for all configurations func (r *ccipChainReader) prepareBatchRequests() contractreader.ExtendedBatchGetLatestValuesRequest { @@ -1833,9 +1844,9 @@ func (r *ccipChainReader) prepareBatchRequests() contractreader.ExtendedBatchGet dynamicConfig offRampDynamicChainConfig selectorsAndConf selectorsAndConfigs rmnRemoteAddress []byte - // rmnDigestHeader rmnDigestHeader - // rmnVersionConfig versionedConfig - // feeQuoterConfig feeQuoterStaticConfig + rmnDigestHeader rmnDigestHeader + rmnVersionConfig versionedConfig + feeQuoterConfig feeQuoterStaticConfig ) return contractreader.ExtendedBatchGetLatestValuesRequest{ @@ -1875,23 +1886,23 @@ func (r *ccipChainReader) prepareBatchRequests() contractreader.ExtendedBatchGet Params: map[string]any{}, ReturnVal: &rmnRemoteAddress, }}, - // consts.ContractNameRMNRemote: { - // { - // ReadName: consts.MethodNameGetReportDigestHeader, - // Params: map[string]any{}, - // ReturnVal: &rmnDigestHeader, - // }, - // { - // ReadName: consts.MethodNameGetVersionedConfig, - // Params: map[string]any{}, - // ReturnVal: &rmnVersionConfig, - // }, - // }, - // consts.ContractNameFeeQuoter: {{ - // ReadName: consts.MethodNameFeeQuoterGetStaticConfig, - // Params: map[string]any{}, - // ReturnVal: &feeQuoterConfig, - // }}, + consts.ContractNameRMNRemote: { + { + ReadName: consts.MethodNameGetReportDigestHeader, + Params: map[string]any{}, + ReturnVal: &rmnDigestHeader, + }, + { + ReadName: consts.MethodNameGetVersionedConfig, + Params: map[string]any{}, + ReturnVal: &rmnVersionConfig, + }, + }, + consts.ContractNameFeeQuoter: {{ + ReadName: consts.MethodNameFeeQuoterGetStaticConfig, + Params: map[string]any{}, + ReturnVal: &feeQuoterConfig, + }}, } } @@ -1918,6 +1929,20 @@ func (r *ccipChainReader) updateFromResults(batchResult types.BatchGetLatestValu r.lggr.Infow("Result is", "result", rmnProxy) response.RMNProxy = rmnProxy + case consts.ContractNameRMNRemote: + rmnRemote, err := r.handleRMNRemoteResults(results) + if err != nil { + return NogoResponse{}, fmt.Errorf("handle RMN remote results: %w", err) + } + response.RMNRemote = rmnRemote + + case consts.ContractNameFeeQuoter: + fq, err := r.handleFeeQuoterResults(results) + if err != nil { + return NogoResponse{}, fmt.Errorf("handle fee quoter results: %w", err) + } + response.FeeQuoter = fq + default: r.lggr.Warnw("No handler found for contract", "contract", contract.Name) } @@ -1950,10 +1975,20 @@ func (r *ccipChainReader) handleRMNProxyResults(results []types.BatchReadResult) } type NogoResponse struct { - Offramp OfframpNogoResponse - RMNProxy RMNProxyNogoResponse + Offramp OfframpNogoResponse + RMNProxy RMNProxyNogoResponse + RMNRemote RMNRemoteNogoResponse + FeeQuoter FeeQuoterNogoResponse +} + +type FeeQuoterNogoResponse struct { + FeeQuoterStaticConfig feeQuoterStaticConfig } +type RMNRemoteNogoResponse struct { + RMNRemoteDigestHeader rmnDigestHeader + RMNRemoteVersionedConfig versionedConfig +} type OfframpNogoResponse struct { CommitLatestOCRConfig OCRConfigResponse ExecLatestOCRConfig OCRConfigResponse @@ -2001,6 +2036,44 @@ func (r *ccipChainReader) handleOffRampResults(results []types.BatchReadResult) return response, nil } +// handleRMNRemoteResults processes RMN remote-specific results +func (r *ccipChainReader) handleRMNRemoteResults(results []types.BatchReadResult) (RMNRemoteNogoResponse, error) { + response := RMNRemoteNogoResponse{} + for i, result := range results { + val, err := result.GetResult() + if err != nil { + return RMNRemoteNogoResponse{}, fmt.Errorf("get RMN remote result %d: %w", i, err) + } + switch i { + case 0: + if typed, ok := val.(*rmnDigestHeader); ok { + response.RMNRemoteDigestHeader = *typed + } + case 1: + if typed, ok := val.(*versionedConfig); ok { + response.RMNRemoteVersionedConfig = *typed + } + } + } + return response, nil +} + +// handleFeeQuoterResults processes fee quoter-specific results +func (r *ccipChainReader) handleFeeQuoterResults(results []types.BatchReadResult) (FeeQuoterNogoResponse, error) { + response := FeeQuoterNogoResponse{} + + if len(results) > 0 { + val, err := results[0].GetResult() + if err != nil { + return FeeQuoterNogoResponse{}, fmt.Errorf("get fee quoter result: %w", err) + } + if typed, ok := val.(*feeQuoterStaticConfig); ok { + response.FeeQuoterStaticConfig = *typed + } + } + return response, nil +} + type OCRConfigResponse struct { OCRConfig OCRConfig } From 68528070eafed22da6880b0da2da92551d358191 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Mon, 3 Feb 2025 17:51:11 +0400 Subject: [PATCH 24/35] fqstaticConfig --- pkg/reader/ccip.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 3b2293810..351eeab04 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1096,16 +1096,24 @@ func (r *ccipChainReader) getDestFeeQuoterStaticConfig(ctx context.Context) (fee consts.MethodNameFeeQuoterGetStaticConfig, &staticConfig, ) - if err != nil { return feeQuoterStaticConfig{}, fmt.Errorf("unable to lookup fee quoter (offramp static config): %w", err) } - if len(staticConfig.LinkToken) == 0 { + result, err := r.refresh(ctx) + if err != nil { + return feeQuoterStaticConfig{}, fmt.Errorf("refresh: %w", err) + } + + staticConfigBatch := result.FeeQuoter.FeeQuoterStaticConfig + + r.lggr.Infow("got fee quoter static config", "staticConfig", staticConfig, "staticConfigBatch", staticConfigBatch) + + if len(staticConfigBatch.LinkToken) == 0 { return feeQuoterStaticConfig{}, fmt.Errorf("link token address is empty") } - return staticConfig, nil + return staticConfigBatch, nil } // getFeeQuoterTokenPriceUSD gets the token price in USD of the given token address from the FeeQuoter contract on the From 2be6fddf75eab5563924f44e2033f1357fc630d4 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Tue, 4 Feb 2025 12:19:00 +0400 Subject: [PATCH 25/35] cache --- commit/factory.go | 2 + execute/factory.go | 2 + pkg/reader/cache.go | 111 +++++++++++++++++++++++++++++++++++ pkg/reader/ccip_interface.go | 48 ++++++++++++++- 4 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 pkg/reader/cache.go diff --git a/commit/factory.go b/commit/factory.go index 16763d1bf..8edcfc34a 100644 --- a/commit/factory.go +++ b/commit/factory.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "time" sel "github.com/smartcontractkit/chain-selectors" @@ -182,6 +183,7 @@ func (p *PluginFactory) NewReportingPlugin(ctx context.Context, config ocr3types p.ocrConfig.Config.ChainSelector, p.ocrConfig.Config.OfframpAddress, p.extraDataCodec, + readerpkg.WithCache(30*time.Second), ) // The node supports the chain that the token prices are on. diff --git a/execute/factory.go b/execute/factory.go index 9589c22e3..3ac619cc9 100644 --- a/execute/factory.go +++ b/execute/factory.go @@ -3,6 +3,7 @@ package execute import ( "context" "fmt" + "time" sel "github.com/smartcontractkit/chain-selectors" @@ -144,6 +145,7 @@ func (p PluginFactory) NewReportingPlugin( p.ocrConfig.Config.ChainSelector, p.ocrConfig.Config.OfframpAddress, p.extraDataCodec, + readerpkg.WithCache(30*time.Second), ) tokenDataObserver, err := tokendata.NewConfigBasedCompositeObservers( diff --git a/pkg/reader/cache.go b/pkg/reader/cache.go new file mode 100644 index 000000000..f9a37c0cc --- /dev/null +++ b/pkg/reader/cache.go @@ -0,0 +1,111 @@ +type cache struct { + sync.RWMutex + data NogoResponse + lastRefresh time.Time + refreshPeriod time.Duration +} + +type CachedChainReader struct { + *ccipChainReader + cache *cache +} + +func NewCachedChainReader( + reader *ccipChainReader, + refreshPeriod time.Duration, +) *CachedChainReader { + reader.lggr.Infow("Creating new cached chain reader", + "refreshPeriod", refreshPeriod) + return &CachedChainReader{ + ccipChainReader: reader, + cache: &cache{ + refreshPeriod: refreshPeriod, + }, + } +} + +func (r *CachedChainReader) getCachedResponse(ctx context.Context) (NogoResponse, error) { + r.cache.RLock() + timeSinceLastRefresh := time.Since(r.cache.lastRefresh) + if timeSinceLastRefresh < r.cache.refreshPeriod { + defer r.cache.RUnlock() + r.lggr.Infow("Cache hit", + "timeSinceLastRefresh", timeSinceLastRefresh, + "refreshPeriod", r.cache.refreshPeriod) + return r.cache.data, nil + } + r.cache.RUnlock() + + r.lggr.Infow("Cache miss, refreshing", + "timeSinceLastRefresh", timeSinceLastRefresh, + "refreshPeriod", r.cache.refreshPeriod) + return r.refreshCache(ctx) +} + +func (r *CachedChainReader) refreshCache(ctx context.Context) (NogoResponse, error) { + r.cache.Lock() + defer r.cache.Unlock() + + timeSinceLastRefresh := time.Since(r.cache.lastRefresh) + if timeSinceLastRefresh < r.cache.refreshPeriod { + r.lggr.Infow("Cache was refreshed by another goroutine", + "timeSinceLastRefresh", timeSinceLastRefresh) + return r.cache.data, nil + } + + r.lggr.Infow("Starting cache refresh", + "lastRefresh", r.cache.lastRefresh) + + startTime := time.Now() + newData, err := r.ccipChainReader.refresh(ctx) + refreshDuration := time.Since(startTime) + + if err != nil { + if !r.cache.lastRefresh.IsZero() { + r.lggr.Warnw("Failed to refresh cache, using old data", + "error", err, + "lastRefresh", r.cache.lastRefresh, + "refreshDuration", refreshDuration) + return r.cache.data, nil + } + r.lggr.Errorw("Failed to refresh cache, no old data available", + "error", err, + "refreshDuration", refreshDuration) + return NogoResponse{}, fmt.Errorf("failed to refresh cache: %w", err) + } + + r.cache.data = newData + r.cache.lastRefresh = time.Now() + + r.lggr.Infow("Cache refresh completed", + "refreshDuration", refreshDuration, + "newLastRefresh", r.cache.lastRefresh) + + return newData, nil +} + +func (r *CachedChainReader) refresh(ctx context.Context) (NogoResponse, error) { + return r.getCachedResponse(ctx) +} + +func (r *CachedChainReader) ForceRefresh(ctx context.Context) error { + r.lggr.Infow("Force refreshing cache") + _, err := r.refreshCache(ctx) + if err != nil { + r.lggr.Errorw("Force refresh failed", + "error", err) + } else { + r.lggr.Infow("Force refresh completed successfully") + } + return err +} + +func (r *CachedChainReader) GetCacheStats() (time.Time, time.Duration) { + r.cache.RLock() + defer r.cache.RUnlock() + r.lggr.Infow("Getting cache stats", + "lastRefresh", r.cache.lastRefresh, + "refreshPeriod", r.cache.refreshPeriod, + "timeSinceLastRefresh", time.Since(r.cache.lastRefresh)) + return r.cache.lastRefresh, r.cache.refreshPeriod +} \ No newline at end of file diff --git a/pkg/reader/ccip_interface.go b/pkg/reader/ccip_interface.go index 4a8fb3d90..527ff11e5 100644 --- a/pkg/reader/ccip_interface.go +++ b/pkg/reader/ccip_interface.go @@ -25,6 +25,13 @@ var ( // Currently only one contract per chain per name is supported. type ContractAddresses map[string]map[cciptypes.ChainSelector]cciptypes.UnknownAddress +type ReaderOption func(*readerOptions) + +type readerOptions struct { + enableCache bool + refreshPeriod time.Duration +} + func (ca ContractAddresses) Append(contract string, chain cciptypes.ChainSelector, address []byte) ContractAddresses { resp := ca if resp == nil { @@ -37,6 +44,27 @@ func (ca ContractAddresses) Append(contract string, chain cciptypes.ChainSelecto return resp } +// WithCache enables caching with the specified refresh period +func WithCache(refreshPeriod time.Duration) ReaderOption { + return func(o *readerOptions) { + o.enableCache = true + o.refreshPeriod = refreshPeriod + } +} + +// applyOptions processes the provided options +func applyOptions(opts ...ReaderOption) readerOptions { + options := readerOptions{ + enableCache: false, + refreshPeriod: 30 * time.Second, // default refresh period + } + for _, opt := range opts { + opt(&options) + } + return options +} + +// NewCCIPChainReader creates a new CCIP reader with optional caching func NewCCIPChainReader( ctx context.Context, lggr logger.Logger, @@ -45,8 +73,11 @@ func NewCCIPChainReader( destChain cciptypes.ChainSelector, offrampAddress []byte, extraDataCodec cciptypes.ExtraDataCodec, + opts ...ReaderOption, ) CCIPReader { - return newCCIPChainReaderInternal( + options := applyOptions(opts...) + + reader := newCCIPChainReaderInternal( ctx, lggr, contractReaders, @@ -55,9 +86,15 @@ func NewCCIPChainReader( offrampAddress, extraDataCodec, ) + + if options.enableCache { + return NewCachedChainReader(reader, options.refreshPeriod) + } + return reader } -// NewCCIPReaderWithExtendedContractReaders can be used when you want to directly provide contractreader.Extended +// NewCCIPReaderWithExtendedContractReaders creates a new CCIP reader +// with extended contract readers and optional caching func NewCCIPReaderWithExtendedContractReaders( ctx context.Context, lggr logger.Logger, @@ -66,11 +103,18 @@ func NewCCIPReaderWithExtendedContractReaders( destChain cciptypes.ChainSelector, offrampAddress []byte, extraDataCodec cciptypes.ExtraDataCodec, + opts ...ReaderOption, ) CCIPReader { + options := applyOptions(opts...) + cr := newCCIPChainReaderInternal(ctx, lggr, nil, contractWriters, destChain, offrampAddress, extraDataCodec) for ch, extendedCr := range contractReaders { cr.WithExtendedContractReader(ch, extendedCr) } + + if options.enableCache { + return NewCachedChainReader(cr, options.refreshPeriod) + } return cr } From df7fb9d3988c8f1829c8b0ab08ee46250f90c9ee Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Tue, 4 Feb 2025 12:23:23 +0400 Subject: [PATCH 26/35] fix --- pkg/reader/cache.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pkg/reader/cache.go b/pkg/reader/cache.go index f9a37c0cc..d131a7643 100644 --- a/pkg/reader/cache.go +++ b/pkg/reader/cache.go @@ -1,3 +1,12 @@ +package reader + +import ( + "context" + "fmt" + "sync" + "time" +) + type cache struct { sync.RWMutex data NogoResponse @@ -108,4 +117,4 @@ func (r *CachedChainReader) GetCacheStats() (time.Time, time.Duration) { "refreshPeriod", r.cache.refreshPeriod, "timeSinceLastRefresh", time.Since(r.cache.lastRefresh)) return r.cache.lastRefresh, r.cache.refreshPeriod -} \ No newline at end of file +} From fe6895d7ac3ad9c0d067e6c6a3ba4ad709e10ca0 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Tue, 4 Feb 2025 15:30:13 +0400 Subject: [PATCH 27/35] usage cache --- pkg/reader/cache.go | 163 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 139 insertions(+), 24 deletions(-) diff --git a/pkg/reader/cache.go b/pkg/reader/cache.go index d131a7643..d1419d9a8 100644 --- a/pkg/reader/cache.go +++ b/pkg/reader/cache.go @@ -5,8 +5,17 @@ import ( "fmt" "sync" "time" + + rmntypes "github.com/smartcontractkit/chainlink-ccip/commit/merkleroot/rmn/types" + "github.com/smartcontractkit/chainlink-ccip/internal/plugintypes" + "github.com/smartcontractkit/chainlink-ccip/pkg/consts" + cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + plugintypes2 "github.com/smartcontractkit/chainlink-ccip/plugintypes" + "github.com/smartcontractkit/chainlink-common/pkg/types" ) +var _ CCIPReader = (*CachedChainReader)(nil) + type cache struct { sync.RWMutex data NogoResponse @@ -15,8 +24,8 @@ type cache struct { } type CachedChainReader struct { - *ccipChainReader - cache *cache + ccipReader *ccipChainReader + cache *cache } func NewCachedChainReader( @@ -26,7 +35,7 @@ func NewCachedChainReader( reader.lggr.Infow("Creating new cached chain reader", "refreshPeriod", refreshPeriod) return &CachedChainReader{ - ccipChainReader: reader, + ccipReader: reader, cache: &cache{ refreshPeriod: refreshPeriod, }, @@ -34,18 +43,19 @@ func NewCachedChainReader( } func (r *CachedChainReader) getCachedResponse(ctx context.Context) (NogoResponse, error) { + r.ccipReader.lggr.Infow("Getting cached response") r.cache.RLock() timeSinceLastRefresh := time.Since(r.cache.lastRefresh) if timeSinceLastRefresh < r.cache.refreshPeriod { defer r.cache.RUnlock() - r.lggr.Infow("Cache hit", + r.ccipReader.lggr.Infow("Cache hit", "timeSinceLastRefresh", timeSinceLastRefresh, "refreshPeriod", r.cache.refreshPeriod) return r.cache.data, nil } r.cache.RUnlock() - r.lggr.Infow("Cache miss, refreshing", + r.ccipReader.lggr.Infow("Cache miss, refreshing", "timeSinceLastRefresh", timeSinceLastRefresh, "refreshPeriod", r.cache.refreshPeriod) return r.refreshCache(ctx) @@ -57,27 +67,27 @@ func (r *CachedChainReader) refreshCache(ctx context.Context) (NogoResponse, err timeSinceLastRefresh := time.Since(r.cache.lastRefresh) if timeSinceLastRefresh < r.cache.refreshPeriod { - r.lggr.Infow("Cache was refreshed by another goroutine", + r.ccipReader.lggr.Infow("Cache was refreshed by another goroutine", "timeSinceLastRefresh", timeSinceLastRefresh) return r.cache.data, nil } - r.lggr.Infow("Starting cache refresh", + r.ccipReader.lggr.Infow("Starting cache refresh", "lastRefresh", r.cache.lastRefresh) startTime := time.Now() - newData, err := r.ccipChainReader.refresh(ctx) + newData, err := r.ccipReader.refresh(ctx) refreshDuration := time.Since(startTime) if err != nil { if !r.cache.lastRefresh.IsZero() { - r.lggr.Warnw("Failed to refresh cache, using old data", + r.ccipReader.lggr.Warnw("Failed to refresh cache, using old data", "error", err, "lastRefresh", r.cache.lastRefresh, "refreshDuration", refreshDuration) return r.cache.data, nil } - r.lggr.Errorw("Failed to refresh cache, no old data available", + r.ccipReader.lggr.Errorw("Failed to refresh cache, no old data available", "error", err, "refreshDuration", refreshDuration) return NogoResponse{}, fmt.Errorf("failed to refresh cache: %w", err) @@ -86,7 +96,7 @@ func (r *CachedChainReader) refreshCache(ctx context.Context) (NogoResponse, err r.cache.data = newData r.cache.lastRefresh = time.Now() - r.lggr.Infow("Cache refresh completed", + r.ccipReader.lggr.Infow("Cache refresh completed", "refreshDuration", refreshDuration, "newLastRefresh", r.cache.lastRefresh) @@ -97,24 +107,129 @@ func (r *CachedChainReader) refresh(ctx context.Context) (NogoResponse, error) { return r.getCachedResponse(ctx) } +// CCIPReader interface implementation +func (r *CachedChainReader) GetOffRampConfigDigest(ctx context.Context, pluginType uint8) ([32]byte, error) { + resp, err := r.refresh(ctx) + if err != nil { + return [32]byte{}, err + } + + var respFromBatch OCRConfigResponse + if pluginType == consts.PluginTypeCommit { + respFromBatch = resp.Offramp.CommitLatestOCRConfig + } else { + respFromBatch = resp.Offramp.ExecLatestOCRConfig + } + + return respFromBatch.OCRConfig.ConfigInfo.ConfigDigest, nil +} + +func (r *CachedChainReader) GetRMNRemoteConfig(ctx context.Context) (rmntypes.RemoteConfig, error) { + resp, err := r.refresh(ctx) + if err != nil { + return rmntypes.RemoteConfig{}, err + } + + // Here we need to construct the RMN config from our cached response + return rmntypes.RemoteConfig{ + ContractAddress: resp.RMNProxy.RMNRemoteAddress, + ConfigDigest: resp.RMNRemote.RMNRemoteVersionedConfig.Config.RMNHomeContractConfigDigest, + Signers: r.buildSigners(resp.RMNRemote.RMNRemoteVersionedConfig.Config.Signers), + FSign: resp.RMNRemote.RMNRemoteVersionedConfig.Config.F, + ConfigVersion: resp.RMNRemote.RMNRemoteVersionedConfig.Version, + RmnReportVersion: resp.RMNRemote.RMNRemoteDigestHeader.DigestHeader, + }, nil +} + +func (r *CachedChainReader) buildSigners(signers []signer) []rmntypes.RemoteSignerInfo { + result := make([]rmntypes.RemoteSignerInfo, 0, len(signers)) + for _, s := range signers { + result = append(result, rmntypes.RemoteSignerInfo{ + OnchainPublicKey: s.OnchainPublicKey, + NodeIndex: s.NodeIndex, + }) + } + return result +} + +// Forward other CCIPReader interface methods to the underlying reader +func (r *CachedChainReader) CommitReportsGTETimestamp(ctx context.Context, ts time.Time, limit int) ([]plugintypes2.CommitPluginReportWithMeta, error) { + return r.ccipReader.CommitReportsGTETimestamp(ctx, ts, limit) +} + +func (r *CachedChainReader) ExecutedMessages(ctx context.Context, source cciptypes.ChainSelector, seqNumRange cciptypes.SeqNumRange) ([]cciptypes.SeqNum, error) { + return r.ccipReader.ExecutedMessages(ctx, source, seqNumRange) +} + +func (r *CachedChainReader) MsgsBetweenSeqNums(ctx context.Context, sourceChainSelector cciptypes.ChainSelector, seqNumRange cciptypes.SeqNumRange) ([]cciptypes.Message, error) { + return r.ccipReader.MsgsBetweenSeqNums(ctx, sourceChainSelector, seqNumRange) +} + +func (r *CachedChainReader) GetExpectedNextSequenceNumber(ctx context.Context, sourceChainSelector cciptypes.ChainSelector) (cciptypes.SeqNum, error) { + return r.ccipReader.GetExpectedNextSequenceNumber(ctx, sourceChainSelector) +} + +func (r *CachedChainReader) NextSeqNum(ctx context.Context, chains []cciptypes.ChainSelector) (map[cciptypes.ChainSelector]cciptypes.SeqNum, error) { + return r.ccipReader.NextSeqNum(ctx, chains) +} + +func (r *CachedChainReader) Nonces(ctx context.Context, sourceChainSelector cciptypes.ChainSelector, addresses []string) (map[string]uint64, error) { + return r.ccipReader.Nonces(ctx, sourceChainSelector, addresses) +} + +func (r *CachedChainReader) GetChainsFeeComponents(ctx context.Context, chains []cciptypes.ChainSelector) map[cciptypes.ChainSelector]types.ChainFeeComponents { + return r.ccipReader.GetChainsFeeComponents(ctx, chains) +} + +func (r *CachedChainReader) GetDestChainFeeComponents(ctx context.Context) (types.ChainFeeComponents, error) { + return r.ccipReader.GetDestChainFeeComponents(ctx) +} + +func (r *CachedChainReader) GetWrappedNativeTokenPriceUSD(ctx context.Context, selectors []cciptypes.ChainSelector) map[cciptypes.ChainSelector]cciptypes.BigInt { + return r.ccipReader.GetWrappedNativeTokenPriceUSD(ctx, selectors) +} + +func (r *CachedChainReader) GetChainFeePriceUpdate(ctx context.Context, selectors []cciptypes.ChainSelector) map[cciptypes.ChainSelector]plugintypes.TimestampedBig { + return r.ccipReader.GetChainFeePriceUpdate(ctx, selectors) +} + +func (r *CachedChainReader) GetRmnCurseInfo(ctx context.Context, sourceChainSelectors []cciptypes.ChainSelector) (*CurseInfo, error) { + return r.ccipReader.GetRmnCurseInfo(ctx, sourceChainSelectors) +} + +func (r *CachedChainReader) GetLatestPriceSeqNr(ctx context.Context) (uint64, error) { + return r.ccipReader.GetLatestPriceSeqNr(ctx) +} + +func (r *CachedChainReader) GetMedianDataAvailabilityGasConfig(ctx context.Context) (cciptypes.DataAvailabilityGasConfig, error) { + return r.ccipReader.GetMedianDataAvailabilityGasConfig(ctx) +} + +func (r *CachedChainReader) DiscoverContracts(ctx context.Context) (ContractAddresses, error) { + return r.ccipReader.DiscoverContracts(ctx) +} + +func (r *CachedChainReader) Sync(ctx context.Context, contracts ContractAddresses) error { + return r.ccipReader.Sync(ctx, contracts) +} + +func (r *CachedChainReader) GetContractAddress(contractName string, chain cciptypes.ChainSelector) ([]byte, error) { + return r.ccipReader.GetContractAddress(contractName, chain) +} + +func (r *CachedChainReader) LinkPriceUSD(ctx context.Context) (cciptypes.BigInt, error) { + return r.ccipReader.LinkPriceUSD(ctx) +} + +// ForceRefresh forces a cache refresh regardless of the refresh period func (r *CachedChainReader) ForceRefresh(ctx context.Context) error { - r.lggr.Infow("Force refreshing cache") + r.ccipReader.lggr.Infow("Force refreshing cache") _, err := r.refreshCache(ctx) if err != nil { - r.lggr.Errorw("Force refresh failed", + r.ccipReader.lggr.Errorw("Force refresh failed", "error", err) } else { - r.lggr.Infow("Force refresh completed successfully") + r.ccipReader.lggr.Infow("Force refresh completed successfully") } return err } - -func (r *CachedChainReader) GetCacheStats() (time.Time, time.Duration) { - r.cache.RLock() - defer r.cache.RUnlock() - r.lggr.Infow("Getting cache stats", - "lastRefresh", r.cache.lastRefresh, - "refreshPeriod", r.cache.refreshPeriod, - "timeSinceLastRefresh", time.Since(r.cache.lastRefresh)) - return r.cache.lastRefresh, r.cache.refreshPeriod -} From e6b617fb8b17e3a21ed005e8330fa54e2c2f87d7 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Tue, 4 Feb 2025 15:32:42 +0400 Subject: [PATCH 28/35] x --- pkg/reader/ccip.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 351eeab04..593b69405 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1860,6 +1860,7 @@ func (r *ccipChainReader) prepareBatchRequests() contractreader.ExtendedBatchGet return contractreader.ExtendedBatchGetLatestValuesRequest{ consts.ContractNameOffRamp: { { + // x ReadName: consts.MethodNameOffRampLatestConfigDetails, Params: map[string]any{ "ocrPluginType": consts.PluginTypeCommit, @@ -1867,6 +1868,7 @@ func (r *ccipChainReader) prepareBatchRequests() contractreader.ExtendedBatchGet ReturnVal: &commitLatestOCRConfig, }, { + // x ReadName: consts.MethodNameOffRampLatestConfigDetails, Params: map[string]any{ "ocrPluginType": consts.PluginTypeExecute, @@ -1896,11 +1898,13 @@ func (r *ccipChainReader) prepareBatchRequests() contractreader.ExtendedBatchGet }}, consts.ContractNameRMNRemote: { { + // x ReadName: consts.MethodNameGetReportDigestHeader, Params: map[string]any{}, ReturnVal: &rmnDigestHeader, }, { + // x ReadName: consts.MethodNameGetVersionedConfig, Params: map[string]any{}, ReturnVal: &rmnVersionConfig, From 79950a97ede352617aed7791e9244f4d4b8b0580 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Tue, 4 Feb 2025 15:50:23 +0400 Subject: [PATCH 29/35] logging --- pkg/reader/cache.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pkg/reader/cache.go b/pkg/reader/cache.go index d1419d9a8..4b8577397 100644 --- a/pkg/reader/cache.go +++ b/pkg/reader/cache.go @@ -114,6 +114,16 @@ func (r *CachedChainReader) GetOffRampConfigDigest(ctx context.Context, pluginTy return [32]byte{}, err } + readerData, err := r.ccipReader.GetOffRampConfigDigest(ctx, pluginType) + if err != nil { + return [32]byte{}, err + } + + r.ccipReader.lggr.Infow("Getting offramp config digest", + "pluginType", pluginType, + "respfromcache", resp, + "readerData", readerData) + var respFromBatch OCRConfigResponse if pluginType == consts.PluginTypeCommit { respFromBatch = resp.Offramp.CommitLatestOCRConfig @@ -130,6 +140,15 @@ func (r *CachedChainReader) GetRMNRemoteConfig(ctx context.Context) (rmntypes.Re return rmntypes.RemoteConfig{}, err } + respFromReader, err := r.ccipReader.GetRMNRemoteConfig(ctx) + if err != nil { + return rmntypes.RemoteConfig{}, err + } + + r.ccipReader.lggr.Infow("Getting RMN remote config", + "respfromcache", resp, + "readerData", respFromReader) + // Here we need to construct the RMN config from our cached response return rmntypes.RemoteConfig{ ContractAddress: resp.RMNProxy.RMNRemoteAddress, From 41db63d1f81c69ab60b22d60805f07f69c2124cb Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Tue, 4 Feb 2025 16:01:10 +0400 Subject: [PATCH 30/35] better logging --- pkg/reader/cache.go | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/pkg/reader/cache.go b/pkg/reader/cache.go index 4b8577397..2e1168a21 100644 --- a/pkg/reader/cache.go +++ b/pkg/reader/cache.go @@ -119,11 +119,6 @@ func (r *CachedChainReader) GetOffRampConfigDigest(ctx context.Context, pluginTy return [32]byte{}, err } - r.ccipReader.lggr.Infow("Getting offramp config digest", - "pluginType", pluginType, - "respfromcache", resp, - "readerData", readerData) - var respFromBatch OCRConfigResponse if pluginType == consts.PluginTypeCommit { respFromBatch = resp.Offramp.CommitLatestOCRConfig @@ -131,6 +126,11 @@ func (r *CachedChainReader) GetOffRampConfigDigest(ctx context.Context, pluginTy respFromBatch = resp.Offramp.ExecLatestOCRConfig } + r.ccipReader.lggr.Infow("Getting offramp config digest", + "pluginType", pluginType, + "respfromcache", respFromBatch.OCRConfig.ConfigInfo.ConfigDigest, + "readerData", readerData) + return respFromBatch.OCRConfig.ConfigInfo.ConfigDigest, nil } @@ -145,8 +145,17 @@ func (r *CachedChainReader) GetRMNRemoteConfig(ctx context.Context) (rmntypes.Re return rmntypes.RemoteConfig{}, err } + ret := rmntypes.RemoteConfig{ + ContractAddress: resp.RMNProxy.RMNRemoteAddress, + ConfigDigest: resp.RMNRemote.RMNRemoteVersionedConfig.Config.RMNHomeContractConfigDigest, + Signers: r.buildSigners(resp.RMNRemote.RMNRemoteVersionedConfig.Config.Signers), + FSign: resp.RMNRemote.RMNRemoteVersionedConfig.Config.F, + ConfigVersion: resp.RMNRemote.RMNRemoteVersionedConfig.Version, + RmnReportVersion: resp.RMNRemote.RMNRemoteDigestHeader.DigestHeader, + } + r.ccipReader.lggr.Infow("Getting RMN remote config", - "respfromcache", resp, + "respfromcache", ret, "readerData", respFromReader) // Here we need to construct the RMN config from our cached response From 69653959518ee25d6b944b61dbc46abe5da8944c Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Tue, 4 Feb 2025 16:48:27 +0400 Subject: [PATCH 31/35] DiscoverContracts --- pkg/reader/cache.go | 57 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/pkg/reader/cache.go b/pkg/reader/cache.go index 2e1168a21..00e506214 100644 --- a/pkg/reader/cache.go +++ b/pkg/reader/cache.go @@ -6,9 +6,12 @@ import ( "sync" "time" + "golang.org/x/exp/maps" + rmntypes "github.com/smartcontractkit/chainlink-ccip/commit/merkleroot/rmn/types" "github.com/smartcontractkit/chainlink-ccip/internal/plugintypes" "github.com/smartcontractkit/chainlink-ccip/pkg/consts" + "github.com/smartcontractkit/chainlink-ccip/pkg/logutil" cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" plugintypes2 "github.com/smartcontractkit/chainlink-ccip/plugintypes" "github.com/smartcontractkit/chainlink-common/pkg/types" @@ -234,7 +237,59 @@ func (r *CachedChainReader) GetMedianDataAvailabilityGasConfig(ctx context.Conte } func (r *CachedChainReader) DiscoverContracts(ctx context.Context) (ContractAddresses, error) { - return r.ccipReader.DiscoverContracts(ctx) + lggr := logutil.WithContextValues(ctx, r.ccipReader.lggr) + resp := make(ContractAddresses) + + // Get cached response + cachedResp, err := r.refresh(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get cached response: %w", err) + } + + // Discover destination contracts if the dest chain is supported. + if err := validateExtendedReaderExistence(r.ccipReader.contractReaders, r.ccipReader.destChain); err == nil { + // Use data from cache for static and dynamic configs + resp = resp.Append( + consts.ContractNameNonceManager, + r.ccipReader.destChain, + cachedResp.Offramp.StaticConfig.NonceManager) + resp = resp.Append(consts.ContractNameRMNRemote, r.ccipReader.destChain, cachedResp.Offramp.StaticConfig.RmnRemote) + resp = resp.Append(consts.ContractNameFeeQuoter, r.ccipReader.destChain, cachedResp.Offramp.DynamicConfig.FeeQuoter) + + // Process source chain configs from cache + selAndConf := cachedResp.Offramp.SelectorsAndConf + for i, sourceChain := range selAndConf.Selectors { + cfg := selAndConf.SourceChainConfigs[i] + if !cfg.IsEnabled { + continue + } + resp = resp.Append(consts.ContractNameOnRamp, cciptypes.ChainSelector(sourceChain), cfg.OnRamp) + if len(resp[consts.ContractNameRouter][r.ccipReader.destChain]) == 0 { + resp = resp.Append(consts.ContractNameRouter, r.ccipReader.destChain, cfg.Router) + lggr.Infow("appending router contract address", "address", cfg.Router) + } + } + } + + lggr.Infow("discovered contracts from cache", "contracts", resp) + + // The following calls are on dynamically configured chains which may not + // be available when this function is called. + myChains := maps.Keys(r.ccipReader.contractReaders) + + // Read onRamps for FeeQuoter in DynamicConfig. + dynamicConfigs := r.ccipReader.getOnRampDynamicConfigs(ctx, lggr, myChains) + for chain, cfg := range dynamicConfigs { + resp = resp.Append(consts.ContractNameFeeQuoter, chain, cfg.DynamicConfig.FeeQuoter) + } + + // Read onRamps for Router in DestChainConfig. + destChainConfig := r.ccipReader.getOnRampDestChainConfig(ctx, myChains) + for chain, cfg := range destChainConfig { + resp = resp.Append(consts.ContractNameRouter, chain, cfg.Router) + } + + return resp, nil } func (r *CachedChainReader) Sync(ctx context.Context, contracts ContractAddresses) error { From 9dc68571bec4109024471a136ac441f34628c0be Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Tue, 4 Feb 2025 17:17:02 +0400 Subject: [PATCH 32/35] LinkPriceUSD --- pkg/reader/cache.go | 39 ++++++++++++++++++++++++++++++++++++++- pkg/reader/ccip.go | 4 ++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/pkg/reader/cache.go b/pkg/reader/cache.go index 00e506214..42557b5ba 100644 --- a/pkg/reader/cache.go +++ b/pkg/reader/cache.go @@ -2,7 +2,9 @@ package reader import ( "context" + "encoding/hex" "fmt" + "math/big" "sync" "time" @@ -301,7 +303,42 @@ func (r *CachedChainReader) GetContractAddress(contractName string, chain ccipty } func (r *CachedChainReader) LinkPriceUSD(ctx context.Context) (cciptypes.BigInt, error) { - return r.ccipReader.LinkPriceUSD(ctx) + // Ensure we can read from the destination chain + if err := validateExtendedReaderExistence(r.ccipReader.contractReaders, r.ccipReader.destChain); err != nil { + return cciptypes.BigInt{}, fmt.Errorf("failed to validate dest chain reader existence: %w", err) + } + + // Get cached response + cachedResp, err := r.refresh(ctx) + if err != nil { + return cciptypes.BigInt{}, fmt.Errorf("failed to get cached response: %w", err) + } + + // Get the link token from cached fee quoter config + feeQuoterCfg := cachedResp.FeeQuoter.FeeQuoterStaticConfig + if len(feeQuoterCfg.LinkToken) == 0 { + return cciptypes.BigInt{}, fmt.Errorf("link token address is empty in cached response") + } + + // Get the token price + linkPriceUSD, err := r.ccipReader.getFeeQuoterTokenPriceUSD(ctx, feeQuoterCfg.LinkToken) + if err != nil { + return cciptypes.BigInt{}, fmt.Errorf("get LINK price in USD: %w", err) + } + + if linkPriceUSD.Int == nil { + return cciptypes.BigInt{}, fmt.Errorf("LINK price is nil") + } + + if linkPriceUSD.Int.Cmp(big.NewInt(0)) == 0 { + return cciptypes.BigInt{}, fmt.Errorf("LINK price is 0") + } + + r.ccipReader.lggr.Infow("Got LINK price from cache", + "linkToken", hex.EncodeToString(feeQuoterCfg.LinkToken), + "priceUSD", linkPriceUSD) + + return linkPriceUSD, nil } // ForceRefresh forces a cache refresh regardless of the refresh period diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 593b69405..c8735c28c 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1876,22 +1876,26 @@ func (r *ccipChainReader) prepareBatchRequests() contractreader.ExtendedBatchGet ReturnVal: &execLatestOCRConfig, }, { + // x ReadName: consts.MethodNameOffRampGetStaticConfig, Params: map[string]any{}, ReturnVal: &staticConfig, }, { + // x ReadName: consts.MethodNameOffRampGetDynamicConfig, Params: map[string]any{}, ReturnVal: &dynamicConfig, }, { + // x ReadName: consts.MethodNameOffRampGetAllSourceChainConfigs, Params: map[string]any{}, ReturnVal: &selectorsAndConf, }, }, consts.ContractNameRMNProxy: {{ + // x ReadName: consts.MethodNameGetARM, Params: map[string]any{}, ReturnVal: &rmnRemoteAddress, From 5f4ea575580d1275a54692a9764ad6a6398995ae Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Tue, 4 Feb 2025 17:27:07 +0400 Subject: [PATCH 33/35] fix --- pkg/reader/cache.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/reader/cache.go b/pkg/reader/cache.go index 42557b5ba..74c052807 100644 --- a/pkg/reader/cache.go +++ b/pkg/reader/cache.go @@ -154,7 +154,7 @@ func (r *CachedChainReader) GetRMNRemoteConfig(ctx context.Context) (rmntypes.Re ContractAddress: resp.RMNProxy.RMNRemoteAddress, ConfigDigest: resp.RMNRemote.RMNRemoteVersionedConfig.Config.RMNHomeContractConfigDigest, Signers: r.buildSigners(resp.RMNRemote.RMNRemoteVersionedConfig.Config.Signers), - FSign: resp.RMNRemote.RMNRemoteVersionedConfig.Config.F, + FSign: resp.RMNRemote.RMNRemoteVersionedConfig.Config.FSign, ConfigVersion: resp.RMNRemote.RMNRemoteVersionedConfig.Version, RmnReportVersion: resp.RMNRemote.RMNRemoteDigestHeader.DigestHeader, } @@ -168,7 +168,7 @@ func (r *CachedChainReader) GetRMNRemoteConfig(ctx context.Context) (rmntypes.Re ContractAddress: resp.RMNProxy.RMNRemoteAddress, ConfigDigest: resp.RMNRemote.RMNRemoteVersionedConfig.Config.RMNHomeContractConfigDigest, Signers: r.buildSigners(resp.RMNRemote.RMNRemoteVersionedConfig.Config.Signers), - FSign: resp.RMNRemote.RMNRemoteVersionedConfig.Config.F, + FSign: resp.RMNRemote.RMNRemoteVersionedConfig.Config.FSign, ConfigVersion: resp.RMNRemote.RMNRemoteVersionedConfig.Version, RmnReportVersion: resp.RMNRemote.RMNRemoteDigestHeader.DigestHeader, }, nil From 5dfe8d640dd26f5ea28c5f49a36d47c05f9e8c44 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Tue, 4 Feb 2025 17:46:28 +0400 Subject: [PATCH 34/35] fix --- pkg/reader/ccip.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/reader/ccip.go b/pkg/reader/ccip.go index 13813a687..0f17f23c2 100644 --- a/pkg/reader/ccip.go +++ b/pkg/reader/ccip.go @@ -1812,12 +1812,12 @@ var _ CCIPReader = (*ccipChainReader)(nil) func (r *ccipChainReader) refresh(ctx context.Context) (NogoResponse, error) { requests := r.prepareBatchRequests() - batchResult, err := r.contractReaders[r.destChain].ExtendedBatchGetLatestValuesGraceful(ctx, requests) + batchResult, skipped, err := r.contractReaders[r.destChain].ExtendedBatchGetLatestValues(ctx, requests, true) if err != nil { return NogoResponse{}, fmt.Errorf("batch get latest values: %w", err) } // print the batchResult - for contract, results := range batchResult.Results { + for contract, results := range batchResult { r.lggr.Infow("contract is", "contract", contract) for i, result := range results { r.lggr.Infow("result is", "result", result) @@ -1829,15 +1829,15 @@ func (r *ccipChainReader) refresh(ctx context.Context) (NogoResponse, error) { } } - r.lggr.Infow("batchResult.SkippedNoBinds is", "batchResult.SkippedNoBinds", batchResult.SkippedNoBinds) + r.lggr.Infow("batchResult.SkippedNoBinds is", "batchResult.SkippedNoBinds", skipped) // Log skipped contracts if any for debugging // Clear skipped contract values from cache - if len(batchResult.SkippedNoBinds) > 0 { - r.lggr.Infow("some contracts were skipped due to no bindings", "contracts", batchResult.SkippedNoBinds) + if len(skipped) > 0 { + r.lggr.Infow("some contracts were skipped due to no bindings", "contracts", batchResult) // c.clearSkippedContractValues(batchResult.SkippedNoBinds) } - return r.updateFromResults(batchResult.Results) + return r.updateFromResults(batchResult) } type rmnDigestHeader struct { From 66b9b5d3060ee30d2f1d7145852c6b20bb176779 Mon Sep 17 00:00:00 2001 From: nogo <0xnogo@gmail.com> Date: Tue, 4 Feb 2025 18:04:48 +0400 Subject: [PATCH 35/35] lint --- pkg/reader/cache.go | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/pkg/reader/cache.go b/pkg/reader/cache.go index 74c052807..bf76ebac2 100644 --- a/pkg/reader/cache.go +++ b/pkg/reader/cache.go @@ -10,13 +10,14 @@ import ( "golang.org/x/exp/maps" + "github.com/smartcontractkit/chainlink-common/pkg/types" + rmntypes "github.com/smartcontractkit/chainlink-ccip/commit/merkleroot/rmn/types" "github.com/smartcontractkit/chainlink-ccip/internal/plugintypes" "github.com/smartcontractkit/chainlink-ccip/pkg/consts" "github.com/smartcontractkit/chainlink-ccip/pkg/logutil" cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" plugintypes2 "github.com/smartcontractkit/chainlink-ccip/plugintypes" - "github.com/smartcontractkit/chainlink-common/pkg/types" ) var _ CCIPReader = (*CachedChainReader)(nil) @@ -186,47 +187,63 @@ func (r *CachedChainReader) buildSigners(signers []signer) []rmntypes.RemoteSign } // Forward other CCIPReader interface methods to the underlying reader -func (r *CachedChainReader) CommitReportsGTETimestamp(ctx context.Context, ts time.Time, limit int) ([]plugintypes2.CommitPluginReportWithMeta, error) { +func (r *CachedChainReader) CommitReportsGTETimestamp( + ctx context.Context, ts time.Time, limit int) ([]plugintypes2.CommitPluginReportWithMeta, error) { return r.ccipReader.CommitReportsGTETimestamp(ctx, ts, limit) } -func (r *CachedChainReader) ExecutedMessages(ctx context.Context, source cciptypes.ChainSelector, seqNumRange cciptypes.SeqNumRange) ([]cciptypes.SeqNum, error) { +func (r *CachedChainReader) ExecutedMessages( + ctx context.Context, source cciptypes.ChainSelector, seqNumRange cciptypes.SeqNumRange) ([]cciptypes.SeqNum, error) { return r.ccipReader.ExecutedMessages(ctx, source, seqNumRange) } -func (r *CachedChainReader) MsgsBetweenSeqNums(ctx context.Context, sourceChainSelector cciptypes.ChainSelector, seqNumRange cciptypes.SeqNumRange) ([]cciptypes.Message, error) { +func (r *CachedChainReader) MsgsBetweenSeqNums( + ctx context.Context, + sourceChainSelector cciptypes.ChainSelector, + seqNumRange cciptypes.SeqNumRange) ([]cciptypes.Message, error) { return r.ccipReader.MsgsBetweenSeqNums(ctx, sourceChainSelector, seqNumRange) } -func (r *CachedChainReader) GetExpectedNextSequenceNumber(ctx context.Context, sourceChainSelector cciptypes.ChainSelector) (cciptypes.SeqNum, error) { +func (r *CachedChainReader) GetExpectedNextSequenceNumber( + ctx context.Context, sourceChainSelector cciptypes.ChainSelector) (cciptypes.SeqNum, error) { return r.ccipReader.GetExpectedNextSequenceNumber(ctx, sourceChainSelector) } -func (r *CachedChainReader) NextSeqNum(ctx context.Context, chains []cciptypes.ChainSelector) (map[cciptypes.ChainSelector]cciptypes.SeqNum, error) { +func (r *CachedChainReader) NextSeqNum( + ctx context.Context, chains []cciptypes.ChainSelector) (map[cciptypes.ChainSelector]cciptypes.SeqNum, error) { return r.ccipReader.NextSeqNum(ctx, chains) } -func (r *CachedChainReader) Nonces(ctx context.Context, sourceChainSelector cciptypes.ChainSelector, addresses []string) (map[string]uint64, error) { +func (r *CachedChainReader) Nonces( + ctx context.Context, sourceChainSelector cciptypes.ChainSelector, addresses []string) (map[string]uint64, error) { return r.ccipReader.Nonces(ctx, sourceChainSelector, addresses) } -func (r *CachedChainReader) GetChainsFeeComponents(ctx context.Context, chains []cciptypes.ChainSelector) map[cciptypes.ChainSelector]types.ChainFeeComponents { +func (r *CachedChainReader) GetChainsFeeComponents( + ctx context.Context, + chains []cciptypes.ChainSelector) map[cciptypes.ChainSelector]types.ChainFeeComponents { return r.ccipReader.GetChainsFeeComponents(ctx, chains) } -func (r *CachedChainReader) GetDestChainFeeComponents(ctx context.Context) (types.ChainFeeComponents, error) { +func (r *CachedChainReader) GetDestChainFeeComponents( + ctx context.Context) (types.ChainFeeComponents, error) { return r.ccipReader.GetDestChainFeeComponents(ctx) } -func (r *CachedChainReader) GetWrappedNativeTokenPriceUSD(ctx context.Context, selectors []cciptypes.ChainSelector) map[cciptypes.ChainSelector]cciptypes.BigInt { +func (r *CachedChainReader) GetWrappedNativeTokenPriceUSD( + ctx context.Context, selectors []cciptypes.ChainSelector) map[cciptypes.ChainSelector]cciptypes.BigInt { return r.ccipReader.GetWrappedNativeTokenPriceUSD(ctx, selectors) } -func (r *CachedChainReader) GetChainFeePriceUpdate(ctx context.Context, selectors []cciptypes.ChainSelector) map[cciptypes.ChainSelector]plugintypes.TimestampedBig { +func (r *CachedChainReader) GetChainFeePriceUpdate( + ctx context.Context, + selectors []cciptypes.ChainSelector) map[cciptypes.ChainSelector]plugintypes.TimestampedBig { return r.ccipReader.GetChainFeePriceUpdate(ctx, selectors) } -func (r *CachedChainReader) GetRmnCurseInfo(ctx context.Context, sourceChainSelectors []cciptypes.ChainSelector) (*CurseInfo, error) { +func (r *CachedChainReader) GetRmnCurseInfo( + ctx context.Context, + sourceChainSelectors []cciptypes.ChainSelector) (*CurseInfo, error) { return r.ccipReader.GetRmnCurseInfo(ctx, sourceChainSelectors) } @@ -234,7 +251,8 @@ func (r *CachedChainReader) GetLatestPriceSeqNr(ctx context.Context) (uint64, er return r.ccipReader.GetLatestPriceSeqNr(ctx) } -func (r *CachedChainReader) GetMedianDataAvailabilityGasConfig(ctx context.Context) (cciptypes.DataAvailabilityGasConfig, error) { +func (r *CachedChainReader) GetMedianDataAvailabilityGasConfig( + ctx context.Context) (cciptypes.DataAvailabilityGasConfig, error) { return r.ccipReader.GetMedianDataAvailabilityGasConfig(ctx) }