diff --git a/.changeset/five-nails-fold.md b/.changeset/five-nails-fold.md new file mode 100644 index 00000000000..8ddd72a71d1 --- /dev/null +++ b/.changeset/five-nails-fold.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +#updated Changed TelemetryIngress.UniConn default to false diff --git a/.changeset/warm-experts-promise.md b/.changeset/warm-experts-promise.md new file mode 100644 index 00000000000..4ee25d4b61a --- /dev/null +++ b/.changeset/warm-experts-promise.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +Remove PriceMin and TipCapMin check from attempt builder #internal diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bafde6de0e2..7bdec1a61f6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -11,7 +11,7 @@ # Services /core/services/directrequest @smartcontractkit/keepers -/core/services/feeds @smartcontractkit/FMS +/core/services/feeds @smartcontractkit/op-core @eutopian @yevshev /core/services/synchronization/telem @smartcontractkit/realtime /core/capabilities/ccip @smartcontractkit/ccip-offchain diff --git a/.github/workflows/on-demand-keeper-smoke-tests.yml b/.github/workflows/on-demand-keeper-smoke-tests.yml index 23626c2c98a..a0ed71c0a06 100644 --- a/.github/workflows/on-demand-keeper-smoke-tests.yml +++ b/.github/workflows/on-demand-keeper-smoke-tests.yml @@ -136,7 +136,7 @@ jobs: - name: Run Tests uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/run-tests@d2f9642bcc24a73400568756f24b72c188ac7a9a # v2.3.31 with: - test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage -hidepassingtests=false -hidepassinglogs + test_command_to_run: cd ./integration-tests && go test -timeout 30m -count=1 -json -test.parallel=${{ matrix.product.nodes }} ${{ steps.build-go-test-command.outputs.run_command }} 2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage -hidepassingtests=false test_download_vendor_packages_command: cd ./integration-tests && go mod download test_config_chainlink_version: ${{ inputs.evm-ref || github.sha }} test_config_selected_networks: ${{ env.SELECTED_NETWORKS }} diff --git a/.github/workflows/run-e2e-tests-reusable-workflow.yml b/.github/workflows/run-e2e-tests-reusable-workflow.yml index 44ce2bfd02a..220c6862040 100644 --- a/.github/workflows/run-e2e-tests-reusable-workflow.yml +++ b/.github/workflows/run-e2e-tests-reusable-workflow.yml @@ -563,7 +563,7 @@ jobs: E2E_TEST_PYROSCOPE_KEY: ${{ matrix.tests.pyroscope_env != '' && secrets.QA_PYROSCOPE_KEY || '' }} E2E_TEST_PYROSCOPE_ENABLED: ${{ matrix.tests.pyroscope_env != '' && 'true' || '' }} with: - test_command_to_run: ${{ matrix.tests.test_cmd }} ${{ matrix.tests.test_cmd_opts || '2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage -hidepassingtests=false -hidepassinglogs' }} + test_command_to_run: ${{ matrix.tests.test_cmd }} ${{ matrix.tests.test_cmd_opts || '2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage -hidepassingtests=false' }} test_download_vendor_packages_command: cd $(dirname ${{ matrix.tests.path }}) && go mod download test_secrets_override_base64: ${{ secrets.TEST_SECRETS_OVERRIDE_BASE64 }} test_config_override_path: ${{ env.TEST_CONFIG_OVERRIDE_PATH }} @@ -780,7 +780,7 @@ jobs: E2E_TEST_PYROSCOPE_ENABLED: ${{ matrix.tests.pyroscope_env != '' && 'true' || '' }} DATABASE_URL: postgresql://postgres:node@localhost:5432/chainlink_test?sslmode=disable with: - test_command_to_run: ${{ matrix.tests.test_cmd }} ${{ matrix.tests.test_cmd_opts || '2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage -hidepassingtests=false -hidepassinglogs' }} + test_command_to_run: ${{ matrix.tests.test_cmd }} ${{ matrix.tests.test_cmd_opts || '2>&1 | tee /tmp/gotest.log | gotestloghelper -ci -singlepackage -hidepassingtests=false' }} test_download_vendor_packages_command: make gomod test_secrets_override_base64: ${{ secrets.TEST_SECRETS_OVERRIDE_BASE64 }} test_config_override_path: ${{ env.TEST_CONFIG_OVERRIDE_PATH }} diff --git a/.mockery.yaml b/.mockery.yaml index 599aa1e65ee..b22875e3f9f 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -348,7 +348,6 @@ packages: Codec: config: dir: core/services/relay/evm/mocks - ContractReader: ChainWriter: github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_onramp: config: @@ -588,3 +587,6 @@ packages: github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer: interfaces: ORM: + github.com/smartcontractkit/chainlink/v2/core/capabilities/targets: + interfaces: + ContractValueGetter: \ No newline at end of file diff --git a/contracts/STYLE_GUIDE.md b/contracts/STYLE_GUIDE.md index f29c129bd01..0f1370be3d7 100644 --- a/contracts/STYLE_GUIDE.md +++ b/contracts/STYLE_GUIDE.md @@ -33,6 +33,7 @@ We will be looking into `forge fmt`, but for now, we still use `prettier`. This will help massively during audits and onboarding new team members. - Headers should be used to group functionality, the following header style and length are recommended. - Don’t use headers for a single function, or to say “getters”. Group by functionality e.g. the `Tokens and pools`, or `fees` logic within the CCIP OnRamp. +- Comments should start with a capital letter and end with a period. ```solidity // ================================================================ @@ -419,4 +420,3 @@ function setConfig(uint64 _foo, uint64 _bar, uint64 _baz) external { ``` rule: `tbd` - diff --git a/core/capabilities/targets/mocks/contract_reader.go b/core/capabilities/targets/mocks/contract_reader.go deleted file mode 100644 index dd92195ec2b..00000000000 --- a/core/capabilities/targets/mocks/contract_reader.go +++ /dev/null @@ -1,533 +0,0 @@ -// Code generated by mockery v2.43.2. DO NOT EDIT. - -package mocks - -import ( - context "context" - - query "github.com/smartcontractkit/chainlink-common/pkg/types/query" - primitives "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" - mock "github.com/stretchr/testify/mock" - - types "github.com/smartcontractkit/chainlink-common/pkg/types" -) - -// ContractReader is an autogenerated mock type for the ContractReader type -type ContractReader struct { - mock.Mock -} - -type ContractReader_Expecter struct { - mock *mock.Mock -} - -func (_m *ContractReader) EXPECT() *ContractReader_Expecter { - return &ContractReader_Expecter{mock: &_m.Mock} -} - -// BatchGetLatestValues provides a mock function with given fields: ctx, request -func (_m *ContractReader) BatchGetLatestValues(ctx context.Context, request types.BatchGetLatestValuesRequest) (types.BatchGetLatestValuesResult, error) { - ret := _m.Called(ctx, request) - - if len(ret) == 0 { - panic("no return value specified for BatchGetLatestValues") - } - - var r0 types.BatchGetLatestValuesResult - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, types.BatchGetLatestValuesRequest) (types.BatchGetLatestValuesResult, error)); ok { - return rf(ctx, request) - } - if rf, ok := ret.Get(0).(func(context.Context, types.BatchGetLatestValuesRequest) types.BatchGetLatestValuesResult); ok { - r0 = rf(ctx, request) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(types.BatchGetLatestValuesResult) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, types.BatchGetLatestValuesRequest) error); ok { - r1 = rf(ctx, request) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ContractReader_BatchGetLatestValues_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BatchGetLatestValues' -type ContractReader_BatchGetLatestValues_Call struct { - *mock.Call -} - -// BatchGetLatestValues is a helper method to define mock.On call -// - ctx context.Context -// - request types.BatchGetLatestValuesRequest -func (_e *ContractReader_Expecter) BatchGetLatestValues(ctx interface{}, request interface{}) *ContractReader_BatchGetLatestValues_Call { - return &ContractReader_BatchGetLatestValues_Call{Call: _e.mock.On("BatchGetLatestValues", ctx, request)} -} - -func (_c *ContractReader_BatchGetLatestValues_Call) Run(run func(ctx context.Context, request types.BatchGetLatestValuesRequest)) *ContractReader_BatchGetLatestValues_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(types.BatchGetLatestValuesRequest)) - }) - return _c -} - -func (_c *ContractReader_BatchGetLatestValues_Call) Return(_a0 types.BatchGetLatestValuesResult, _a1 error) *ContractReader_BatchGetLatestValues_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *ContractReader_BatchGetLatestValues_Call) RunAndReturn(run func(context.Context, types.BatchGetLatestValuesRequest) (types.BatchGetLatestValuesResult, error)) *ContractReader_BatchGetLatestValues_Call { - _c.Call.Return(run) - return _c -} - -// Bind provides a mock function with given fields: ctx, bindings -func (_m *ContractReader) Bind(ctx context.Context, bindings []types.BoundContract) error { - ret := _m.Called(ctx, bindings) - - if len(ret) == 0 { - panic("no return value specified for Bind") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, []types.BoundContract) error); ok { - r0 = rf(ctx, bindings) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// ContractReader_Bind_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Bind' -type ContractReader_Bind_Call struct { - *mock.Call -} - -// Bind is a helper method to define mock.On call -// - ctx context.Context -// - bindings []types.BoundContract -func (_e *ContractReader_Expecter) Bind(ctx interface{}, bindings interface{}) *ContractReader_Bind_Call { - return &ContractReader_Bind_Call{Call: _e.mock.On("Bind", ctx, bindings)} -} - -func (_c *ContractReader_Bind_Call) Run(run func(ctx context.Context, bindings []types.BoundContract)) *ContractReader_Bind_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].([]types.BoundContract)) - }) - return _c -} - -func (_c *ContractReader_Bind_Call) Return(_a0 error) *ContractReader_Bind_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *ContractReader_Bind_Call) RunAndReturn(run func(context.Context, []types.BoundContract) error) *ContractReader_Bind_Call { - _c.Call.Return(run) - return _c -} - -// Close provides a mock function with given fields: -func (_m *ContractReader) Close() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Close") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// ContractReader_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' -type ContractReader_Close_Call struct { - *mock.Call -} - -// Close is a helper method to define mock.On call -func (_e *ContractReader_Expecter) Close() *ContractReader_Close_Call { - return &ContractReader_Close_Call{Call: _e.mock.On("Close")} -} - -func (_c *ContractReader_Close_Call) Run(run func()) *ContractReader_Close_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *ContractReader_Close_Call) Return(_a0 error) *ContractReader_Close_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *ContractReader_Close_Call) RunAndReturn(run func() error) *ContractReader_Close_Call { - _c.Call.Return(run) - return _c -} - -// GetLatestValue provides a mock function with given fields: ctx, readIdentifier, confidenceLevel, params, returnVal -func (_m *ContractReader) GetLatestValue(ctx context.Context, readIdentifier string, confidenceLevel primitives.ConfidenceLevel, params interface{}, returnVal interface{}) error { - ret := _m.Called(ctx, readIdentifier, confidenceLevel, params, returnVal) - - if len(ret) == 0 { - panic("no return value specified for GetLatestValue") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, primitives.ConfidenceLevel, interface{}, interface{}) error); ok { - r0 = rf(ctx, readIdentifier, confidenceLevel, params, returnVal) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// ContractReader_GetLatestValue_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLatestValue' -type ContractReader_GetLatestValue_Call struct { - *mock.Call -} - -// GetLatestValue is a helper method to define mock.On call -// - ctx context.Context -// - readIdentifier string -// - confidenceLevel primitives.ConfidenceLevel -// - params interface{} -// - returnVal interface{} -func (_e *ContractReader_Expecter) GetLatestValue(ctx interface{}, readIdentifier interface{}, confidenceLevel interface{}, params interface{}, returnVal interface{}) *ContractReader_GetLatestValue_Call { - return &ContractReader_GetLatestValue_Call{Call: _e.mock.On("GetLatestValue", ctx, readIdentifier, confidenceLevel, params, returnVal)} -} - -func (_c *ContractReader_GetLatestValue_Call) Run(run func(ctx context.Context, readIdentifier string, confidenceLevel primitives.ConfidenceLevel, params interface{}, returnVal interface{})) *ContractReader_GetLatestValue_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(primitives.ConfidenceLevel), args[3].(interface{}), args[4].(interface{})) - }) - return _c -} - -func (_c *ContractReader_GetLatestValue_Call) Return(_a0 error) *ContractReader_GetLatestValue_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *ContractReader_GetLatestValue_Call) RunAndReturn(run func(context.Context, string, primitives.ConfidenceLevel, interface{}, interface{}) error) *ContractReader_GetLatestValue_Call { - _c.Call.Return(run) - return _c -} - -// HealthReport provides a mock function with given fields: -func (_m *ContractReader) HealthReport() map[string]error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for HealthReport") - } - - var r0 map[string]error - if rf, ok := ret.Get(0).(func() map[string]error); ok { - r0 = rf() - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(map[string]error) - } - } - - return r0 -} - -// ContractReader_HealthReport_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HealthReport' -type ContractReader_HealthReport_Call struct { - *mock.Call -} - -// HealthReport is a helper method to define mock.On call -func (_e *ContractReader_Expecter) HealthReport() *ContractReader_HealthReport_Call { - return &ContractReader_HealthReport_Call{Call: _e.mock.On("HealthReport")} -} - -func (_c *ContractReader_HealthReport_Call) Run(run func()) *ContractReader_HealthReport_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *ContractReader_HealthReport_Call) Return(_a0 map[string]error) *ContractReader_HealthReport_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *ContractReader_HealthReport_Call) RunAndReturn(run func() map[string]error) *ContractReader_HealthReport_Call { - _c.Call.Return(run) - return _c -} - -// Name provides a mock function with given fields: -func (_m *ContractReader) Name() string { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Name") - } - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// ContractReader_Name_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Name' -type ContractReader_Name_Call struct { - *mock.Call -} - -// Name is a helper method to define mock.On call -func (_e *ContractReader_Expecter) Name() *ContractReader_Name_Call { - return &ContractReader_Name_Call{Call: _e.mock.On("Name")} -} - -func (_c *ContractReader_Name_Call) Run(run func()) *ContractReader_Name_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *ContractReader_Name_Call) Return(_a0 string) *ContractReader_Name_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *ContractReader_Name_Call) RunAndReturn(run func() string) *ContractReader_Name_Call { - _c.Call.Return(run) - return _c -} - -// QueryKey provides a mock function with given fields: ctx, contract, filter, limitAndSort, sequenceDataType -func (_m *ContractReader) QueryKey(ctx context.Context, contract types.BoundContract, filter query.KeyFilter, limitAndSort query.LimitAndSort, sequenceDataType interface{}) ([]types.Sequence, error) { - ret := _m.Called(ctx, contract, filter, limitAndSort, sequenceDataType) - - if len(ret) == 0 { - panic("no return value specified for QueryKey") - } - - var r0 []types.Sequence - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, types.BoundContract, query.KeyFilter, query.LimitAndSort, interface{}) ([]types.Sequence, error)); ok { - return rf(ctx, contract, filter, limitAndSort, sequenceDataType) - } - if rf, ok := ret.Get(0).(func(context.Context, types.BoundContract, query.KeyFilter, query.LimitAndSort, interface{}) []types.Sequence); ok { - r0 = rf(ctx, contract, filter, limitAndSort, sequenceDataType) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]types.Sequence) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, types.BoundContract, query.KeyFilter, query.LimitAndSort, interface{}) error); ok { - r1 = rf(ctx, contract, filter, limitAndSort, sequenceDataType) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// ContractReader_QueryKey_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'QueryKey' -type ContractReader_QueryKey_Call struct { - *mock.Call -} - -// QueryKey is a helper method to define mock.On call -// - ctx context.Context -// - contract types.BoundContract -// - filter query.KeyFilter -// - limitAndSort query.LimitAndSort -// - sequenceDataType interface{} -func (_e *ContractReader_Expecter) QueryKey(ctx interface{}, contract interface{}, filter interface{}, limitAndSort interface{}, sequenceDataType interface{}) *ContractReader_QueryKey_Call { - return &ContractReader_QueryKey_Call{Call: _e.mock.On("QueryKey", ctx, contract, filter, limitAndSort, sequenceDataType)} -} - -func (_c *ContractReader_QueryKey_Call) Run(run func(ctx context.Context, contract types.BoundContract, filter query.KeyFilter, limitAndSort query.LimitAndSort, sequenceDataType interface{})) *ContractReader_QueryKey_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(types.BoundContract), args[2].(query.KeyFilter), args[3].(query.LimitAndSort), args[4].(interface{})) - }) - return _c -} - -func (_c *ContractReader_QueryKey_Call) Return(_a0 []types.Sequence, _a1 error) *ContractReader_QueryKey_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *ContractReader_QueryKey_Call) RunAndReturn(run func(context.Context, types.BoundContract, query.KeyFilter, query.LimitAndSort, interface{}) ([]types.Sequence, error)) *ContractReader_QueryKey_Call { - _c.Call.Return(run) - return _c -} - -// Ready provides a mock function with given fields: -func (_m *ContractReader) Ready() error { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Ready") - } - - var r0 error - if rf, ok := ret.Get(0).(func() error); ok { - r0 = rf() - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// ContractReader_Ready_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Ready' -type ContractReader_Ready_Call struct { - *mock.Call -} - -// Ready is a helper method to define mock.On call -func (_e *ContractReader_Expecter) Ready() *ContractReader_Ready_Call { - return &ContractReader_Ready_Call{Call: _e.mock.On("Ready")} -} - -func (_c *ContractReader_Ready_Call) Run(run func()) *ContractReader_Ready_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *ContractReader_Ready_Call) Return(_a0 error) *ContractReader_Ready_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *ContractReader_Ready_Call) RunAndReturn(run func() error) *ContractReader_Ready_Call { - _c.Call.Return(run) - return _c -} - -// Start provides a mock function with given fields: _a0 -func (_m *ContractReader) Start(_a0 context.Context) error { - ret := _m.Called(_a0) - - if len(ret) == 0 { - panic("no return value specified for Start") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context) error); ok { - r0 = rf(_a0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// ContractReader_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start' -type ContractReader_Start_Call struct { - *mock.Call -} - -// Start is a helper method to define mock.On call -// - _a0 context.Context -func (_e *ContractReader_Expecter) Start(_a0 interface{}) *ContractReader_Start_Call { - return &ContractReader_Start_Call{Call: _e.mock.On("Start", _a0)} -} - -func (_c *ContractReader_Start_Call) Run(run func(_a0 context.Context)) *ContractReader_Start_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context)) - }) - return _c -} - -func (_c *ContractReader_Start_Call) Return(_a0 error) *ContractReader_Start_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *ContractReader_Start_Call) RunAndReturn(run func(context.Context) error) *ContractReader_Start_Call { - _c.Call.Return(run) - return _c -} - -// Unbind provides a mock function with given fields: ctx, bindings -func (_m *ContractReader) Unbind(ctx context.Context, bindings []types.BoundContract) error { - ret := _m.Called(ctx, bindings) - - if len(ret) == 0 { - panic("no return value specified for Unbind") - } - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, []types.BoundContract) error); ok { - r0 = rf(ctx, bindings) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// ContractReader_Unbind_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Unbind' -type ContractReader_Unbind_Call struct { - *mock.Call -} - -// Unbind is a helper method to define mock.On call -// - ctx context.Context -// - bindings []types.BoundContract -func (_e *ContractReader_Expecter) Unbind(ctx interface{}, bindings interface{}) *ContractReader_Unbind_Call { - return &ContractReader_Unbind_Call{Call: _e.mock.On("Unbind", ctx, bindings)} -} - -func (_c *ContractReader_Unbind_Call) Run(run func(ctx context.Context, bindings []types.BoundContract)) *ContractReader_Unbind_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].([]types.BoundContract)) - }) - return _c -} - -func (_c *ContractReader_Unbind_Call) Return(_a0 error) *ContractReader_Unbind_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *ContractReader_Unbind_Call) RunAndReturn(run func(context.Context, []types.BoundContract) error) *ContractReader_Unbind_Call { - _c.Call.Return(run) - return _c -} - -// NewContractReader creates a new instance of ContractReader. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewContractReader(t interface { - mock.TestingT - Cleanup(func()) -}) *ContractReader { - mock := &ContractReader{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/capabilities/targets/mocks/contract_value_getter.go b/core/capabilities/targets/mocks/contract_value_getter.go new file mode 100644 index 00000000000..2621de45876 --- /dev/null +++ b/core/capabilities/targets/mocks/contract_value_getter.go @@ -0,0 +1,136 @@ +// Code generated by mockery v2.43.2. DO NOT EDIT. + +package mocks + +import ( + context "context" + + primitives "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" + mock "github.com/stretchr/testify/mock" + + types "github.com/smartcontractkit/chainlink-common/pkg/types" +) + +// ContractValueGetter is an autogenerated mock type for the ContractValueGetter type +type ContractValueGetter struct { + mock.Mock +} + +type ContractValueGetter_Expecter struct { + mock *mock.Mock +} + +func (_m *ContractValueGetter) EXPECT() *ContractValueGetter_Expecter { + return &ContractValueGetter_Expecter{mock: &_m.Mock} +} + +// Bind provides a mock function with given fields: _a0, _a1 +func (_m *ContractValueGetter) Bind(_a0 context.Context, _a1 []types.BoundContract) error { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for Bind") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, []types.BoundContract) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ContractValueGetter_Bind_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Bind' +type ContractValueGetter_Bind_Call struct { + *mock.Call +} + +// Bind is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 []types.BoundContract +func (_e *ContractValueGetter_Expecter) Bind(_a0 interface{}, _a1 interface{}) *ContractValueGetter_Bind_Call { + return &ContractValueGetter_Bind_Call{Call: _e.mock.On("Bind", _a0, _a1)} +} + +func (_c *ContractValueGetter_Bind_Call) Run(run func(_a0 context.Context, _a1 []types.BoundContract)) *ContractValueGetter_Bind_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].([]types.BoundContract)) + }) + return _c +} + +func (_c *ContractValueGetter_Bind_Call) Return(_a0 error) *ContractValueGetter_Bind_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ContractValueGetter_Bind_Call) RunAndReturn(run func(context.Context, []types.BoundContract) error) *ContractValueGetter_Bind_Call { + _c.Call.Return(run) + return _c +} + +// GetLatestValue provides a mock function with given fields: _a0, _a1, _a2, _a3, _a4 +func (_m *ContractValueGetter) GetLatestValue(_a0 context.Context, _a1 string, _a2 primitives.ConfidenceLevel, _a3 interface{}, _a4 interface{}) error { + ret := _m.Called(_a0, _a1, _a2, _a3, _a4) + + if len(ret) == 0 { + panic("no return value specified for GetLatestValue") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, primitives.ConfidenceLevel, interface{}, interface{}) error); ok { + r0 = rf(_a0, _a1, _a2, _a3, _a4) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ContractValueGetter_GetLatestValue_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLatestValue' +type ContractValueGetter_GetLatestValue_Call struct { + *mock.Call +} + +// GetLatestValue is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 string +// - _a2 primitives.ConfidenceLevel +// - _a3 interface{} +// - _a4 interface{} +func (_e *ContractValueGetter_Expecter) GetLatestValue(_a0 interface{}, _a1 interface{}, _a2 interface{}, _a3 interface{}, _a4 interface{}) *ContractValueGetter_GetLatestValue_Call { + return &ContractValueGetter_GetLatestValue_Call{Call: _e.mock.On("GetLatestValue", _a0, _a1, _a2, _a3, _a4)} +} + +func (_c *ContractValueGetter_GetLatestValue_Call) Run(run func(_a0 context.Context, _a1 string, _a2 primitives.ConfidenceLevel, _a3 interface{}, _a4 interface{})) *ContractValueGetter_GetLatestValue_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(primitives.ConfidenceLevel), args[3].(interface{}), args[4].(interface{})) + }) + return _c +} + +func (_c *ContractValueGetter_GetLatestValue_Call) Return(_a0 error) *ContractValueGetter_GetLatestValue_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ContractValueGetter_GetLatestValue_Call) RunAndReturn(run func(context.Context, string, primitives.ConfidenceLevel, interface{}, interface{}) error) *ContractValueGetter_GetLatestValue_Call { + _c.Call.Return(run) + return _c +} + +// NewContractValueGetter creates a new instance of ContractValueGetter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewContractValueGetter(t interface { + mock.TestingT + Cleanup(func()) +}) *ContractValueGetter { + mock := &ContractValueGetter{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/capabilities/targets/write_target.go b/core/capabilities/targets/write_target.go index c8f33ff8232..85c8011410a 100644 --- a/core/capabilities/targets/write_target.go +++ b/core/capabilities/targets/write_target.go @@ -23,7 +23,7 @@ var ( ) type WriteTarget struct { - cr commontypes.ContractReader + cr ContractValueGetter cw commontypes.ChainWriter binding commontypes.BoundContract forwarderAddress string @@ -50,7 +50,19 @@ type TransmissionInfo struct { // TODO: Make this part of the on-chain capability configuration const FORWARDER_CONTRACT_LOGIC_GAS_COST = 100_000 -func NewWriteTarget(lggr logger.Logger, id string, cr commontypes.ContractReader, cw commontypes.ChainWriter, forwarderAddress string, txGasLimit uint64) *WriteTarget { +type ContractValueGetter interface { + Bind(context.Context, []commontypes.BoundContract) error + GetLatestValue(context.Context, string, primitives.ConfidenceLevel, any, any) error +} + +func NewWriteTarget( + lggr logger.Logger, + id string, + cr ContractValueGetter, + cw commontypes.ChainWriter, + forwarderAddress string, + txGasLimit uint64, +) *WriteTarget { info := capabilities.MustNewCapabilityInfo( id, capabilities.CapabilityTypeTarget, diff --git a/core/capabilities/targets/write_target_test.go b/core/capabilities/targets/write_target_test.go index 1dd5323d0ff..96df31bd3cc 100644 --- a/core/capabilities/targets/write_target_test.go +++ b/core/capabilities/targets/write_target_test.go @@ -28,7 +28,7 @@ func TestWriteTarget(t *testing.T) { ctx := context.Background() cw := mocks.NewChainWriter(t) - cr := mocks.NewContractReader(t) + cr := mocks.NewContractValueGetter(t) forwarderA := testutils.NewAddress() forwarderAddr := forwarderA.Hex() diff --git a/core/chains/evm/txmgr/attempts.go b/core/chains/evm/txmgr/attempts.go index c284ee77bd4..2fc444071e7 100644 --- a/core/chains/evm/txmgr/attempts.go +++ b/core/chains/evm/txmgr/attempts.go @@ -34,8 +34,6 @@ type evmTxAttemptBuilder struct { type evmTxAttemptBuilderFeeConfig interface { EIP1559DynamicFees() bool - TipCapMin() *assets.Wei - PriceMin() *assets.Wei PriceMaxKey(common.Address) *assets.Wei LimitDefault() uint64 } @@ -172,7 +170,7 @@ func (c *evmTxAttemptBuilder) NewEmptyTxAttempt(ctx context.Context, nonce evmty } func (c *evmTxAttemptBuilder) newDynamicFeeAttempt(ctx context.Context, etx Tx, fee gas.DynamicFee, gasLimit uint64) (attempt TxAttempt, err error) { - if err = validateDynamicFeeGas(c.feeConfig, c.feeConfig.TipCapMin(), fee, etx); err != nil { + if err = validateDynamicFeeGas(c.feeConfig, fee, etx); err != nil { return attempt, pkgerrors.Wrap(err, "error validating gas") } @@ -208,7 +206,7 @@ type keySpecificEstimator interface { // validateDynamicFeeGas is a sanity check - we have other checks elsewhere, but this // makes sure we _never_ create an invalid attempt -func validateDynamicFeeGas(kse keySpecificEstimator, tipCapMinimum *assets.Wei, fee gas.DynamicFee, etx Tx) error { +func validateDynamicFeeGas(kse keySpecificEstimator, fee gas.DynamicFee, etx Tx) error { gasTipCap, gasFeeCap := fee.TipCap, fee.FeeCap if gasTipCap == nil { @@ -235,11 +233,6 @@ func validateDynamicFeeGas(kse keySpecificEstimator, tipCapMinimum *assets.Wei, if gasFeeCap.Cmp(max) > 0 { return pkgerrors.Errorf("cannot create tx attempt: specified gas fee cap of %s would exceed max configured gas price of %s for key %s", gasFeeCap.String(), max.String(), etx.FromAddress.String()) } - // Tip must be above minimum - minTip := tipCapMinimum - if gasTipCap.Cmp(minTip) < 0 { - return pkgerrors.Errorf("cannot create tx attempt: specified gas tip cap of %s is below min configured gas tip of %s for key %s", gasTipCap.String(), minTip.String(), etx.FromAddress.String()) - } return nil } @@ -257,7 +250,7 @@ func newDynamicFeeTransaction(nonce uint64, to common.Address, value *big.Int, g } func (c *evmTxAttemptBuilder) newLegacyAttempt(ctx context.Context, etx Tx, gasPrice *assets.Wei, gasLimit uint64) (attempt TxAttempt, err error) { - if err = validateLegacyGas(c.feeConfig, c.feeConfig.PriceMin(), gasPrice, etx); err != nil { + if err = validateLegacyGas(c.feeConfig, gasPrice, etx); err != nil { return attempt, pkgerrors.Wrap(err, "error validating gas") } @@ -290,7 +283,7 @@ func (c *evmTxAttemptBuilder) newLegacyAttempt(ctx context.Context, etx Tx, gasP // validateLegacyGas is a sanity check - we have other checks elsewhere, but this // makes sure we _never_ create an invalid attempt -func validateLegacyGas(kse keySpecificEstimator, minGasPriceWei, gasPrice *assets.Wei, etx Tx) error { +func validateLegacyGas(kse keySpecificEstimator, gasPrice *assets.Wei, etx Tx) error { if gasPrice == nil { panic("gas price missing") } @@ -298,10 +291,6 @@ func validateLegacyGas(kse keySpecificEstimator, minGasPriceWei, gasPrice *asset if gasPrice.Cmp(max) > 0 { return pkgerrors.Errorf("cannot create tx attempt: specified gas price of %s would exceed max configured gas price of %s for key %s", gasPrice.String(), max.String(), etx.FromAddress.String()) } - min := minGasPriceWei - if gasPrice.Cmp(min) < 0 { - return pkgerrors.Errorf("cannot create tx attempt: specified gas price of %s is below min configured gas price of %s for key %s", gasPrice.String(), min.String(), etx.FromAddress.String()) - } return nil } diff --git a/core/chains/evm/txmgr/attempts_test.go b/core/chains/evm/txmgr/attempts_test.go index 5c43368fcc4..df88835384f 100644 --- a/core/chains/evm/txmgr/attempts_test.go +++ b/core/chains/evm/txmgr/attempts_test.go @@ -171,9 +171,6 @@ func TestTxm_NewDynamicFeeTx(t *testing.T) { {"ignores global min gas price", assets.GWei(5), assets.GWei(5), func(c *toml.EVMConfig) { c.GasEstimator.PriceMin = assets.GWei(6) }, ""}, - {"tip cap below min allowed", assets.GWei(5), assets.GWei(5), func(c *toml.EVMConfig) { - c.GasEstimator.TipCapMin = assets.GWei(6) - }, "specified gas tip cap of 5 gwei is below min configured gas tip of 6 gwei"}, } for _, tt := range cases { diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 10e9002eab0..439076cfa88 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -1620,31 +1620,17 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { // configured for the transaction pool. // This is a configuration error by the node operator, since it means they set the base gas level too low. underpricedError := "transaction underpriced" - localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, testutils.FixtureChainID) - // Check gas tip cap verification - evmcfg2 := evmtest.NewChainScopedConfig(t, configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) - c.EVM[0].GasEstimator.TipCapDefault = assets.NewWeiI(0) - })) - ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() - eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg2, &testCheckerFactory{}, false, nonceTracker) - - retryable, err := eb2.ProcessUnstartedTxs(ctx, fromAddress) - require.Error(t, err) - require.Contains(t, err.Error(), "specified gas tip cap of 0 is below min configured gas tip of 1 wei for key") - assert.True(t, retryable) - gasTipCapDefault := assets.NewWeiI(42) - evmcfg2 = evmtest.NewChainScopedConfig(t, configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + evmcfg2 := evmtest.NewChainScopedConfig(t, configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].GasEstimator.EIP1559DynamicFees = ptr(true) c.EVM[0].GasEstimator.TipCapDefault = gasTipCapDefault })) - localNextNonce = getLocalNextNonce(t, nonceTracker, fromAddress) + localNextNonce := getLocalNextNonce(t, nonceTracker, fromAddress) ethClient.On("PendingNonceAt", mock.Anything, fromAddress).Return(localNextNonce, nil).Once() - eb2 = NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg2, &testCheckerFactory{}, false, nonceTracker) + eb2 := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, cfg, evmcfg2, &testCheckerFactory{}, false, nonceTracker) // Second was underpriced but above minimum ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { @@ -1659,7 +1645,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { return tx.Nonce() == localNextNonce && tx.GasTipCap().Cmp(big.NewInt(0).Add(gasTipCapDefault.ToInt(), big.NewInt(0).Mul(evmcfg2.EVM().GasEstimator().BumpMin().ToInt(), big.NewInt(2)))) == 0 }), fromAddress).Return(commonclient.Successful, nil).Once() - retryable, err = eb2.ProcessUnstartedTxs(ctx, fromAddress) + retryable, err := eb2.ProcessUnstartedTxs(ctx, fromAddress) require.NoError(t, err) assert.False(t, retryable) diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index d29223a31e1..dde898ed3b1 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -89,7 +89,7 @@ LeaseRefreshInterval = '1s' # Default [TelemetryIngress] # UniConn toggles which ws connection style is used. -UniConn = true # Default +UniConn = false # Default # Logging toggles verbose logging of the raw telemetry messages being sent. Logging = false # Default # BufferSize is the number of telemetry messages to buffer before dropping new ones. diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 747c4f20ec4..70572648640 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -22,7 +22,7 @@ require ( github.com/prometheus/client_golang v1.20.0 github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chainlink-automation v1.0.4 - github.com/smartcontractkit/chainlink-common v0.2.2-0.20240911181800-d00d5184ffaa + github.com/smartcontractkit/chainlink-common v0.2.2-0.20240913161926-ce5d667907ce github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20240717100443-f6226e09bee7 github.com/spf13/cobra v1.8.1 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index ad91e2472c2..a4d95878153 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1083,8 +1083,8 @@ github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8um github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= github.com/smartcontractkit/chainlink-ccip v0.0.0-20240911145028-d346e3ace978 h1:BPuehkAQ8R112SlTitukSdKYRJMY3zkvaQS4VSTNn0Q= github.com/smartcontractkit/chainlink-ccip v0.0.0-20240911145028-d346e3ace978/go.mod h1:X1f4CKlR1RilSgzArQv5HNvMrVSt+Zloihm3REwxhdQ= -github.com/smartcontractkit/chainlink-common v0.2.2-0.20240911181800-d00d5184ffaa h1:vG4aRggHzNDFTmMFemhhUAzqTfG159w0+RYjO7/cJ5E= -github.com/smartcontractkit/chainlink-common v0.2.2-0.20240911181800-d00d5184ffaa/go.mod h1:sjiiPwd4KsYOCf68MwL86EKphdXeT66EY7j53WH5DCc= +github.com/smartcontractkit/chainlink-common v0.2.2-0.20240913161926-ce5d667907ce h1:qXS0aWiDFDoLRCB+kSGnzp77iYT2luflUyzE5BnNmpY= +github.com/smartcontractkit/chainlink-common v0.2.2-0.20240913161926-ce5d667907ce/go.mod h1:sjiiPwd4KsYOCf68MwL86EKphdXeT66EY7j53WH5DCc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 h1:lTGIOQYLk1Ufn++X/AvZnt6VOcuhste5yp+C157No/Q= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7/go.mod h1:BMYE1vC/pGmdFSsOJdPrAA0/4gZ0Xo0SxTMdGspBtRo= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240906125718-9f0a98d32fbc h1:tRmTlaoAt+7FakMXXgeCuRPmzzBo5jsGpeCVvcU6KMc= diff --git a/core/services/chainlink/config_telemetry_ingress_test.go b/core/services/chainlink/config_telemetry_ingress_test.go index c371b465a2b..64e85b5493e 100644 --- a/core/services/chainlink/config_telemetry_ingress_test.go +++ b/core/services/chainlink/config_telemetry_ingress_test.go @@ -17,7 +17,7 @@ func TestTelemetryIngressConfig(t *testing.T) { ticfg := cfg.TelemetryIngress() assert.True(t, ticfg.Logging()) - assert.True(t, ticfg.UniConn()) + assert.False(t, ticfg.UniConn()) assert.Equal(t, uint(1234), ticfg.BufferSize()) assert.Equal(t, uint(4321), ticfg.MaxBatchSize()) assert.Equal(t, time.Minute, ticfg.SendInterval()) diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 1018778b32f..8e157de9049 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -290,7 +290,7 @@ func TestConfig_Marshal(t *testing.T) { }, } full.TelemetryIngress = toml.TelemetryIngress{ - UniConn: ptr(true), + UniConn: ptr(false), Logging: ptr(true), BufferSize: ptr[uint16](1234), MaxBatchSize: ptr[uint16](4321), @@ -840,7 +840,7 @@ LeaseDuration = '1m0s' LeaseRefreshInterval = '1s' `}, {"TelemetryIngress", Config{Core: toml.Core{TelemetryIngress: full.TelemetryIngress}}, `[TelemetryIngress] -UniConn = true +UniConn = false Logging = true BufferSize = 1234 MaxBatchSize = 4321 diff --git a/core/services/chainlink/testdata/config-empty-effective.toml b/core/services/chainlink/testdata/config-empty-effective.toml index f78c98896d0..4cfe5e2086c 100644 --- a/core/services/chainlink/testdata/config-empty-effective.toml +++ b/core/services/chainlink/testdata/config-empty-effective.toml @@ -35,7 +35,7 @@ LeaseDuration = '10s' LeaseRefreshInterval = '1s' [TelemetryIngress] -UniConn = true +UniConn = false Logging = false BufferSize = 100 MaxBatchSize = 50 diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index e000ff82d40..eb69cee8b72 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -35,7 +35,7 @@ LeaseDuration = '1m0s' LeaseRefreshInterval = '1s' [TelemetryIngress] -UniConn = true +UniConn = false Logging = true BufferSize = 1234 MaxBatchSize = 4321 diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index fc11ed10b1d..776481ed6a9 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -35,7 +35,7 @@ LeaseDuration = '10s' LeaseRefreshInterval = '1s' [TelemetryIngress] -UniConn = true +UniConn = false Logging = false BufferSize = 100 MaxBatchSize = 50 diff --git a/core/services/relay/evm/chain_reader.go b/core/services/relay/evm/chain_reader.go index c9cc18e34a7..800631b858d 100644 --- a/core/services/relay/evm/chain_reader.go +++ b/core/services/relay/evm/chain_reader.go @@ -34,6 +34,7 @@ type ChainReaderService interface { } type chainReader struct { + commontypes.UnimplementedContractReader lggr logger.Logger ht logpoller.HeadTracker lp logpoller.LogPoller diff --git a/core/web/resolver/testdata/config-empty-effective.toml b/core/web/resolver/testdata/config-empty-effective.toml index f78c98896d0..4cfe5e2086c 100644 --- a/core/web/resolver/testdata/config-empty-effective.toml +++ b/core/web/resolver/testdata/config-empty-effective.toml @@ -35,7 +35,7 @@ LeaseDuration = '10s' LeaseRefreshInterval = '1s' [TelemetryIngress] -UniConn = true +UniConn = false Logging = false BufferSize = 100 MaxBatchSize = 50 diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index a13a6b9db59..ee413a610e4 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -35,7 +35,7 @@ LeaseDuration = '1m0s' LeaseRefreshInterval = '1s' [TelemetryIngress] -UniConn = true +UniConn = false Logging = true BufferSize = 1234 MaxBatchSize = 4321 diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index a3853dd2b44..210894d6162 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -35,7 +35,7 @@ LeaseDuration = '10s' LeaseRefreshInterval = '1s' [TelemetryIngress] -UniConn = true +UniConn = false Logging = false BufferSize = 100 MaxBatchSize = 50 diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 2f339dfda4c..c9262577f10 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -256,7 +256,7 @@ LeaseRefreshInterval determines how often to refresh the lease lock. Also contro ## TelemetryIngress ```toml [TelemetryIngress] -UniConn = true # Default +UniConn = false # Default Logging = false # Default BufferSize = 100 # Default MaxBatchSize = 50 # Default @@ -268,7 +268,7 @@ UseBatchSend = true # Default ### UniConn ```toml -UniConn = true # Default +UniConn = false # Default ``` UniConn toggles which ws connection style is used. diff --git a/go.mod b/go.mod index 6f9b0e2bebc..e3c64fca6b4 100644 --- a/go.mod +++ b/go.mod @@ -75,7 +75,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.23 github.com/smartcontractkit/chainlink-automation v1.0.4 github.com/smartcontractkit/chainlink-ccip v0.0.0-20240911145028-d346e3ace978 - github.com/smartcontractkit/chainlink-common v0.2.2-0.20240911181800-d00d5184ffaa + github.com/smartcontractkit/chainlink-common v0.2.2-0.20240913161926-ce5d667907ce github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240906125718-9f0a98d32fbc github.com/smartcontractkit/chainlink-feeds v0.0.0-20240910155501-42f20443189f diff --git a/go.sum b/go.sum index 2ef165dcb5c..5ee578f7b2c 100644 --- a/go.sum +++ b/go.sum @@ -1044,8 +1044,8 @@ github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8um github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= github.com/smartcontractkit/chainlink-ccip v0.0.0-20240911145028-d346e3ace978 h1:BPuehkAQ8R112SlTitukSdKYRJMY3zkvaQS4VSTNn0Q= github.com/smartcontractkit/chainlink-ccip v0.0.0-20240911145028-d346e3ace978/go.mod h1:X1f4CKlR1RilSgzArQv5HNvMrVSt+Zloihm3REwxhdQ= -github.com/smartcontractkit/chainlink-common v0.2.2-0.20240911181800-d00d5184ffaa h1:vG4aRggHzNDFTmMFemhhUAzqTfG159w0+RYjO7/cJ5E= -github.com/smartcontractkit/chainlink-common v0.2.2-0.20240911181800-d00d5184ffaa/go.mod h1:sjiiPwd4KsYOCf68MwL86EKphdXeT66EY7j53WH5DCc= +github.com/smartcontractkit/chainlink-common v0.2.2-0.20240913161926-ce5d667907ce h1:qXS0aWiDFDoLRCB+kSGnzp77iYT2luflUyzE5BnNmpY= +github.com/smartcontractkit/chainlink-common v0.2.2-0.20240913161926-ce5d667907ce/go.mod h1:sjiiPwd4KsYOCf68MwL86EKphdXeT66EY7j53WH5DCc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 h1:lTGIOQYLk1Ufn++X/AvZnt6VOcuhste5yp+C157No/Q= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7/go.mod h1:BMYE1vC/pGmdFSsOJdPrAA0/4gZ0Xo0SxTMdGspBtRo= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240906125718-9f0a98d32fbc h1:tRmTlaoAt+7FakMXXgeCuRPmzzBo5jsGpeCVvcU6KMc= diff --git a/integration-tests/deployment/ccip/add_chain.go b/integration-tests/deployment/ccip/add_chain.go new file mode 100644 index 00000000000..bc997f0dc5e --- /dev/null +++ b/integration-tests/deployment/ccip/add_chain.go @@ -0,0 +1,170 @@ +package ccipdeployment + +import ( + "math/big" + + "github.com/smartcontractkit/ccip-owner-contracts/tools/proposal/mcms" + "github.com/smartcontractkit/ccip-owner-contracts/tools/proposal/timelock" + chainsel "github.com/smartcontractkit/chain-selectors" + + "github.com/smartcontractkit/chainlink-ccip/chainconfig" + "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink/integration-tests/deployment" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" +) + +// NewChainInboundProposal generates a proposal +// to connect the new chain to the existing chains. +func NewChainInboundProposal( + e deployment.Environment, + state CCIPOnChainState, + homeChainSel uint64, + newChainSel uint64, + sources []uint64, +) (*timelock.MCMSWithTimelockProposal, error) { + // Generate proposal which enables new destination (from test router) on all source chains. + var batches []timelock.BatchChainOperation + metaDataPerChain := make(map[mcms.ChainIdentifier]timelock.MCMSWithTimelockChainMetadata) + for _, source := range sources { + chain, _ := chainsel.ChainBySelector(source) + enableOnRampDest, err := state.Chains[source].OnRamp.ApplyDestChainConfigUpdates(SimTransactOpts(), []onramp.OnRampDestChainConfigArgs{ + { + DestChainSelector: newChainSel, + Router: state.Chains[source].TestRouter.Address(), + }, + }) + if err != nil { + return nil, err + } + enableFeeQuoterDest, err := state.Chains[source].FeeQuoter.ApplyDestChainConfigUpdates( + SimTransactOpts(), + []fee_quoter.FeeQuoterDestChainConfigArgs{ + { + DestChainSelector: newChainSel, + DestChainConfig: defaultFeeQuoterDestChainConfig(), + }, + }) + if err != nil { + return nil, err + } + initialPrices, err := state.Chains[source].FeeQuoter.UpdatePrices( + SimTransactOpts(), + fee_quoter.InternalPriceUpdates{ + TokenPriceUpdates: []fee_quoter.InternalTokenPriceUpdate{}, + GasPriceUpdates: []fee_quoter.InternalGasPriceUpdate{ + { + DestChainSelector: newChainSel, + // TODO: parameterize + UsdPerUnitGas: big.NewInt(2e12), + }, + }}) + if err != nil { + return nil, err + } + batches = append(batches, timelock.BatchChainOperation{ + ChainIdentifier: mcms.ChainIdentifier(chain.Selector), + Batch: []mcms.Operation{ + { + // Enable the source in on ramp + To: state.Chains[source].OnRamp.Address(), + Data: enableOnRampDest.Data(), + Value: big.NewInt(0), + }, + { + // Set initial dest prices to unblock testing. + To: state.Chains[source].FeeQuoter.Address(), + Data: initialPrices.Data(), + Value: big.NewInt(0), + }, + { + To: state.Chains[source].FeeQuoter.Address(), + Data: enableFeeQuoterDest.Data(), + Value: big.NewInt(0), + }, + }, + }) + metaDataPerChain[mcms.ChainIdentifier(chain.Selector)] = timelock.MCMSWithTimelockChainMetadata{ + ChainMetadata: mcms.ChainMetadata{ + NonceOffset: 0, + MCMAddress: state.Chains[source].Mcm.Address(), + }, + TimelockAddress: state.Chains[source].Timelock.Address(), + } + } + + // Home chain new don. + // - Add new DONs for destination to home chain + nodes, err := deployment.NodeInfo(e.NodeIDs, e.Offchain) + if err != nil { + return nil, err + } + encodedExtraChainConfig, err := chainconfig.EncodeChainConfig(chainconfig.ChainConfig{ + GasPriceDeviationPPB: ccipocr3.NewBigIntFromInt64(1000), + DAGasPriceDeviationPPB: ccipocr3.NewBigIntFromInt64(0), + OptimisticConfirmations: 1, + }) + if err != nil { + return nil, err + } + chainConfig := SetupConfigInfo(newChainSel, nodes.NonBootstraps().PeerIDs(), + nodes.DefaultF(), encodedExtraChainConfig) + addChain, err := state.Chains[homeChainSel].CCIPConfig.ApplyChainConfigUpdates(SimTransactOpts(), nil, []ccip_config.CCIPConfigTypesChainConfigInfo{ + chainConfig, + }) + if err != nil { + return nil, err + } + + newDONArgs, err := BuildAddDONArgs(e.Logger, state.Chains[newChainSel].OffRamp, e.Chains[newChainSel], nodes.NonBootstraps()) + if err != nil { + return nil, err + } + addDON, err := state.Chains[homeChainSel].CapabilityRegistry.AddDON(SimTransactOpts(), + nodes.NonBootstraps().PeerIDs(), []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ + { + CapabilityId: CCIPCapabilityID, + Config: newDONArgs, + }, + }, false, false, nodes.NonBootstraps().DefaultF()) + if err != nil { + return nil, err + } + homeChain, _ := chainsel.ChainBySelector(homeChainSel) + metaDataPerChain[mcms.ChainIdentifier(homeChain.Selector)] = timelock.MCMSWithTimelockChainMetadata{ + ChainMetadata: mcms.ChainMetadata{ + NonceOffset: 0, + MCMAddress: state.Chains[homeChainSel].Mcm.Address(), + }, + TimelockAddress: state.Chains[homeChainSel].Timelock.Address(), + } + batches = append(batches, timelock.BatchChainOperation{ + ChainIdentifier: mcms.ChainIdentifier(homeChain.Selector), + Batch: []mcms.Operation{ + { + // Add the chain first, don needs it to be there. + To: state.Chains[homeChainSel].CCIPConfig.Address(), + Data: addChain.Data(), + Value: big.NewInt(0), + }, + { + To: state.Chains[homeChainSel].CapabilityRegistry.Address(), + Data: addDON.Data(), + Value: big.NewInt(0), + }, + }, + }) + return timelock.NewMCMSWithTimelockProposal( + "1", + 2004259681, // TODO: should be parameterized and based on current block timestamp. + []mcms.Signature{}, + false, + metaDataPerChain, + "blah", // TODO + batches, + timelock.Schedule, + "0s", // TODO: Should be parameterized. + ) +} diff --git a/integration-tests/deployment/ccip/add_chain_test.go b/integration-tests/deployment/ccip/add_chain_test.go new file mode 100644 index 00000000000..a484bda0f2d --- /dev/null +++ b/integration-tests/deployment/ccip/add_chain_test.go @@ -0,0 +1,157 @@ +package ccipdeployment + +import ( + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/integration-tests/deployment" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +func TestAddChainInbound(t *testing.T) { + // 4 chains where the 4th is added after initial deployment. + e := NewEnvironmentWithCRAndJobs(t, logger.TestLogger(t), 4) + require.Equal(t, len(e.Nodes), 5) + state, err := LoadOnchainState(e.Env, e.Ab) + require.NoError(t, err) + // Take first non-home chain as the new chain. + newChain := e.Env.AllChainSelectorsExcluding([]uint64{e.HomeChainSel})[0] + // We deploy to the rest. + initialDeploy := e.Env.AllChainSelectorsExcluding([]uint64{newChain}) + + ab, err := DeployCCIPContracts(e.Env, DeployCCIPContractConfig{ + HomeChainSel: e.HomeChainSel, + ChainsToDeploy: initialDeploy, + CCIPOnChainState: state, + }) + require.NoError(t, err) + require.NoError(t, e.Ab.Merge(ab)) + state, err = LoadOnchainState(e.Env, e.Ab) + require.NoError(t, err) + + // Connect all the existing lanes. + for _, source := range initialDeploy { + for _, dest := range initialDeploy { + if source != dest { + require.NoError(t, AddLane(e.Env, state, source, dest)) + } + } + } + + // Deploy contracts to new chain + newAddresses, err := DeployChainContracts(e.Env, e.Env.Chains[newChain], deployment.NewMemoryAddressBook()) + require.NoError(t, err) + require.NoError(t, e.Ab.Merge(newAddresses)) + state, err = LoadOnchainState(e.Env, e.Ab) + require.NoError(t, err) + + // Transfer onramp/fq ownership to timelock. + // Enable the new dest on the test router. + for _, source := range initialDeploy { + tx, err := state.Chains[source].OnRamp.TransferOwnership(e.Env.Chains[source].DeployerKey, state.Chains[source].Timelock.Address()) + require.NoError(t, err) + _, err = deployment.ConfirmIfNoError(e.Env.Chains[source], tx, err) + require.NoError(t, err) + tx, err = state.Chains[source].FeeQuoter.TransferOwnership(e.Env.Chains[source].DeployerKey, state.Chains[source].Timelock.Address()) + require.NoError(t, err) + _, err = deployment.ConfirmIfNoError(e.Env.Chains[source], tx, err) + require.NoError(t, err) + tx, err = state.Chains[source].TestRouter.ApplyRampUpdates(e.Env.Chains[source].DeployerKey, []router.RouterOnRamp{ + { + DestChainSelector: newChain, + OnRamp: state.Chains[source].OnRamp.Address(), + }, + }, nil, nil) + _, err = deployment.ConfirmIfNoError(e.Env.Chains[source], tx, err) + require.NoError(t, err) + } + // Transfer CR contract ownership + tx, err := state.Chains[e.HomeChainSel].CapabilityRegistry.TransferOwnership(e.Env.Chains[e.HomeChainSel].DeployerKey, state.Chains[e.HomeChainSel].Timelock.Address()) + require.NoError(t, err) + _, err = deployment.ConfirmIfNoError(e.Env.Chains[e.HomeChainSel], tx, err) + require.NoError(t, err) + tx, err = state.Chains[e.HomeChainSel].CCIPConfig.TransferOwnership(e.Env.Chains[e.HomeChainSel].DeployerKey, state.Chains[e.HomeChainSel].Timelock.Address()) + require.NoError(t, err) + _, err = deployment.ConfirmIfNoError(e.Env.Chains[e.HomeChainSel], tx, err) + require.NoError(t, err) + + acceptOwnershipProposal, err := GenerateAcceptOwnershipProposal(state, e.HomeChainSel, initialDeploy) + require.NoError(t, err) + acceptOwnershipExec := SignProposal(t, e.Env, acceptOwnershipProposal) + // Apply the accept ownership proposal to all the chains. + for _, sel := range initialDeploy { + ExecuteProposal(t, e.Env, acceptOwnershipExec, state, sel) + } + for _, chain := range initialDeploy { + owner, err2 := state.Chains[chain].OnRamp.Owner(nil) + require.NoError(t, err2) + require.Equal(t, state.Chains[chain].Timelock.Address(), owner) + } + cfgOwner, err := state.Chains[e.HomeChainSel].CCIPConfig.Owner(nil) + require.NoError(t, err) + crOwner, err := state.Chains[e.HomeChainSel].CapabilityRegistry.Owner(nil) + require.NoError(t, err) + require.Equal(t, state.Chains[e.HomeChainSel].Timelock.Address(), cfgOwner) + require.Equal(t, state.Chains[e.HomeChainSel].Timelock.Address(), crOwner) + + // Generate and sign inbound proposal to new 4th chain. + chainInboundProposal, err := NewChainInboundProposal(e.Env, state, e.HomeChainSel, newChain, initialDeploy) + require.NoError(t, err) + chainInboundExec := SignProposal(t, e.Env, chainInboundProposal) + for _, sel := range initialDeploy { + ExecuteProposal(t, e.Env, chainInboundExec, state, sel) + } + + // Now configure the new chain using deployer key (not transferred to timelock yet). + var offRampEnables []offramp.OffRampSourceChainConfigArgs + for _, source := range initialDeploy { + offRampEnables = append(offRampEnables, offramp.OffRampSourceChainConfigArgs{ + Router: state.Chains[newChain].Router.Address(), + SourceChainSelector: source, + IsEnabled: true, + OnRamp: common.LeftPadBytes(state.Chains[source].OnRamp.Address().Bytes(), 32), + }) + } + tx, err = state.Chains[newChain].OffRamp.ApplySourceChainConfigUpdates(e.Env.Chains[newChain].DeployerKey, offRampEnables) + require.NoError(t, err) + _, err = deployment.ConfirmIfNoError(e.Env.Chains[newChain], tx, err) + require.NoError(t, err) + // Set the OCR3 config on new 4th chain to enable the plugin. + latestDON, err := LatestCCIPDON(state.Chains[e.HomeChainSel].CapabilityRegistry) + require.NoError(t, err) + ocrConfigs, err := BuildSetOCR3ConfigArgs(latestDON.Id, state.Chains[e.HomeChainSel].CCIPConfig) + require.NoError(t, err) + tx, err = state.Chains[newChain].OffRamp.SetOCR3Configs(e.Env.Chains[newChain].DeployerKey, ocrConfigs) + require.NoError(t, err) + _, err = deployment.ConfirmIfNoError(e.Env.Chains[newChain], tx, err) + require.NoError(t, err) + + // Assert the inbound lanes to the new chain are wired correctly. + state, err = LoadOnchainState(e.Env, e.Ab) + require.NoError(t, err) + for _, chain := range initialDeploy { + cfg, err2 := state.Chains[chain].OnRamp.GetDestChainConfig(nil, newChain) + require.NoError(t, err2) + assert.Equal(t, cfg.Router, state.Chains[chain].TestRouter.Address()) + fqCfg, err2 := state.Chains[chain].FeeQuoter.GetDestChainConfig(nil, newChain) + require.NoError(t, err2) + assert.True(t, fqCfg.IsEnabled) + s, err2 := state.Chains[newChain].OffRamp.GetSourceChainConfig(nil, chain) + require.NoError(t, err2) + assert.Equal(t, common.LeftPadBytes(state.Chains[chain].OnRamp.Address().Bytes(), 32), s.OnRamp) + } + // Ensure job related logs are up to date. + time.Sleep(30 * time.Second) + require.NoError(t, ReplayAllLogs(e.Nodes, e.Env.Chains)) + + // TODO: Send via all inbound lanes and use parallel helper + // Now that the proposal has been executed we expect to be able to send traffic to this new 4th chain. + seqNr := SendRequest(t, e.Env, state, initialDeploy[0], newChain, true) + ConfirmExecution(t, e.Env.Chains[initialDeploy[0]], e.Env.Chains[newChain], state.Chains[newChain].OffRamp, seqNr) +} diff --git a/integration-tests/deployment/ccip/add_lane.go b/integration-tests/deployment/ccip/add_lane.go index 7ea757f03ac..0e7c01405b1 100644 --- a/integration-tests/deployment/ccip/add_lane.go +++ b/integration-tests/deployment/ccip/add_lane.go @@ -7,8 +7,9 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/smartcontractkit/chainlink/integration-tests/deployment" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" + + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" ) @@ -18,13 +19,13 @@ func AddLane(e deployment.Environment, state CCIPOnChainState, from, to uint64) tx, err := state.Chains[from].Router.ApplyRampUpdates(e.Chains[from].DeployerKey, []router.RouterOnRamp{ { DestChainSelector: to, - OnRamp: state.Chains[from].EvmOnRampV160.Address(), + OnRamp: state.Chains[from].OnRamp.Address(), }, }, []router.RouterOffRamp{}, []router.RouterOffRamp{}) if _, err := deployment.ConfirmIfNoError(e.Chains[from], tx, err); err != nil { return err } - tx, err = state.Chains[from].EvmOnRampV160.ApplyDestChainConfigUpdates(e.Chains[from].DeployerKey, + tx, err = state.Chains[from].OnRamp.ApplyDestChainConfigUpdates(e.Chains[from].DeployerKey, []onramp.OnRampDestChainConfigArgs{ { DestChainSelector: to, @@ -35,7 +36,7 @@ func AddLane(e deployment.Environment, state CCIPOnChainState, from, to uint64) return err } - _, err = state.Chains[from].PriceRegistry.UpdatePrices( + _, err = state.Chains[from].FeeQuoter.UpdatePrices( e.Chains[from].DeployerKey, fee_quoter.InternalPriceUpdates{ TokenPriceUpdates: []fee_quoter.InternalTokenPriceUpdate{ { @@ -57,25 +58,25 @@ func AddLane(e deployment.Environment, state CCIPOnChainState, from, to uint64) return err } - // Enable dest in price registry - tx, err = state.Chains[from].PriceRegistry.ApplyDestChainConfigUpdates(e.Chains[from].DeployerKey, + // Enable dest in fee quoter + tx, err = state.Chains[from].FeeQuoter.ApplyDestChainConfigUpdates(e.Chains[from].DeployerKey, []fee_quoter.FeeQuoterDestChainConfigArgs{ { DestChainSelector: to, - DestChainConfig: defaultPriceRegistryDestChainConfig(), + DestChainConfig: defaultFeeQuoterDestChainConfig(), }, }) if _, err := deployment.ConfirmIfNoError(e.Chains[from], tx, err); err != nil { return err } - tx, err = state.Chains[to].EvmOffRampV160.ApplySourceChainConfigUpdates(e.Chains[to].DeployerKey, + tx, err = state.Chains[to].OffRamp.ApplySourceChainConfigUpdates(e.Chains[to].DeployerKey, []offramp.OffRampSourceChainConfigArgs{ { Router: state.Chains[to].Router.Address(), SourceChainSelector: from, IsEnabled: true, - OnRamp: common.LeftPadBytes(state.Chains[from].EvmOnRampV160.Address().Bytes(), 32), + OnRamp: common.LeftPadBytes(state.Chains[from].OnRamp.Address().Bytes(), 32), }, }) if _, err := deployment.ConfirmIfNoError(e.Chains[to], tx, err); err != nil { @@ -84,14 +85,14 @@ func AddLane(e deployment.Environment, state CCIPOnChainState, from, to uint64) tx, err = state.Chains[to].Router.ApplyRampUpdates(e.Chains[to].DeployerKey, []router.RouterOnRamp{}, []router.RouterOffRamp{}, []router.RouterOffRamp{ { SourceChainSelector: from, - OffRamp: state.Chains[to].EvmOffRampV160.Address(), + OffRamp: state.Chains[to].OffRamp.Address(), }, }) _, err = deployment.ConfirmIfNoError(e.Chains[to], tx, err) return err } -func defaultPriceRegistryDestChainConfig() fee_quoter.FeeQuoterDestChainConfig { +func defaultFeeQuoterDestChainConfig() fee_quoter.FeeQuoterDestChainConfig { // https://github.com/smartcontractkit/ccip/blob/c4856b64bd766f1ddbaf5d13b42d3c4b12efde3a/contracts/src/v0.8/ccip/libraries/Internal.sol#L337-L337 /* ```Solidity @@ -112,9 +113,10 @@ func defaultPriceRegistryDestChainConfig() fee_quoter.FeeQuoterDestChainConfig { DestGasPerDataAvailabilityByte: 100, DestDataAvailabilityMultiplierBps: 1, DefaultTokenDestGasOverhead: 125_000, - DefaultTxGasLimit: 200_000, - GasMultiplierWeiPerEth: 1, - NetworkFeeUSDCents: 1, - ChainFamilySelector: [4]byte(evmFamilySelector), + //DefaultTokenDestBytesOverhead: 32, + DefaultTxGasLimit: 200_000, + GasMultiplierWeiPerEth: 1, + NetworkFeeUSDCents: 1, + ChainFamilySelector: [4]byte(evmFamilySelector), } } diff --git a/integration-tests/deployment/ccip/add_lane_test.go b/integration-tests/deployment/ccip/add_lane_test.go index 567f5ca6856..77b82348e4a 100644 --- a/integration-tests/deployment/ccip/add_lane_test.go +++ b/integration-tests/deployment/ccip/add_lane_test.go @@ -1 +1,57 @@ package ccipdeployment + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +// TestAddLane covers the workflow of adding a lane +// between existing supported chains in CCIP. +func TestAddLane(t *testing.T) { + // TODO: The offchain code doesn't yet support partial lane + // enablement, need to address then re-enable this test. + t.Skip() + e := NewEnvironmentWithCRAndJobs(t, logger.TestLogger(t), 3) + // Here we have CR + nodes set up, but no CCIP contracts deployed. + state, err := LoadOnchainState(e.Env, e.Ab) + require.NoError(t, err) + // Set up CCIP contracts and a DON per chain. + ab, err := DeployCCIPContracts(e.Env, DeployCCIPContractConfig{ + HomeChainSel: e.HomeChainSel, + CCIPOnChainState: state, + }) + require.NoError(t, err) + require.NoError(t, e.Ab.Merge(ab)) + + // We expect no lanes available on any chain. + state, err = LoadOnchainState(e.Env, e.Ab) + require.NoError(t, err) + for _, chain := range state.Chains { + offRamps, err := chain.Router.GetOffRamps(nil) + require.NoError(t, err) + require.Len(t, offRamps, 0) + } + + // Add one lane and send traffic. + from, to := e.Env.AllChainSelectors()[0], e.Env.AllChainSelectors()[1] + require.NoError(t, AddLane(e.Env, state, from, to)) + + for sel, chain := range state.Chains { + offRamps, err := chain.Router.GetOffRamps(nil) + require.NoError(t, err) + if sel == to { + require.Len(t, offRamps, 1) + } else { + require.Len(t, offRamps, 0) + } + } + seqNum := SendRequest(t, e.Env, state, from, to, false) + require.Equal(t, uint64(1), seqNum) + ConfirmExecution(t, e.Env.Chains[from], e.Env.Chains[to], state.Chains[to].OffRamp, seqNum) + + // TODO: Add a second lane, then disable the first and + // ensure we can send on the second but not the first. +} diff --git a/integration-tests/deployment/ccip/changeset/1_cap_reg.go b/integration-tests/deployment/ccip/changeset/1_cap_reg.go index 1929aede02f..58634916235 100644 --- a/integration-tests/deployment/ccip/changeset/1_cap_reg.go +++ b/integration-tests/deployment/ccip/changeset/1_cap_reg.go @@ -1,6 +1,8 @@ package changeset import ( + "github.com/smartcontractkit/ccip-owner-contracts/tools/proposal/timelock" + "github.com/smartcontractkit/chainlink/integration-tests/deployment" ccipdeployment "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip" ) @@ -14,7 +16,7 @@ func Apply0001(env deployment.Environment, homeChainSel uint64) (deployment.Chan return deployment.ChangesetOutput{}, err } return deployment.ChangesetOutput{ - Proposals: []deployment.Proposal{}, + Proposals: []timelock.MCMSWithTimelockProposal{}, AddressBook: ab, JobSpecs: nil, }, nil diff --git a/integration-tests/deployment/ccip/changeset/2_initial_deploy.go b/integration-tests/deployment/ccip/changeset/2_initial_deploy.go index b20ffb2d4ac..93c408bf45a 100644 --- a/integration-tests/deployment/ccip/changeset/2_initial_deploy.go +++ b/integration-tests/deployment/ccip/changeset/2_initial_deploy.go @@ -1,6 +1,8 @@ package changeset import ( + "github.com/smartcontractkit/ccip-owner-contracts/tools/proposal/timelock" + "github.com/smartcontractkit/chainlink/integration-tests/deployment" ccipdeployment "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip" @@ -14,18 +16,14 @@ func Apply0002(env deployment.Environment, c ccipdeployment.DeployCCIPContractCo ab, err := ccipdeployment.DeployCCIPContracts(env, c) if err != nil { env.Logger.Errorw("Failed to deploy CCIP contracts", "err", err, "addresses", ab) - return deployment.ChangesetOutput{}, err + return deployment.ChangesetOutput{}, deployment.MaybeDataErr(err) } js, err := ccipdeployment.NewCCIPJobSpecs(env.NodeIDs, env.Offchain) if err != nil { return deployment.ChangesetOutput{}, err } - proposal, err := ccipdeployment.GenerateAcceptOwnershipProposal(env, env.AllChainSelectors(), ab) - if err != nil { - return deployment.ChangesetOutput{}, err - } return deployment.ChangesetOutput{ - Proposals: []deployment.Proposal{proposal}, + Proposals: []timelock.MCMSWithTimelockProposal{}, AddressBook: ab, // Mapping of which nodes get which jobs. JobSpecs: js, diff --git a/integration-tests/deployment/ccip/changeset/2_initial_deploy_test.go b/integration-tests/deployment/ccip/changeset/2_initial_deploy_test.go index 8098ebaef21..fa0fbb9141b 100644 --- a/integration-tests/deployment/ccip/changeset/2_initial_deploy_test.go +++ b/integration-tests/deployment/ccip/changeset/2_initial_deploy_test.go @@ -8,27 +8,22 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/integration-tests/deployment" "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" + ccipdeployment "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip" jobv1 "github.com/smartcontractkit/chainlink/integration-tests/deployment/jd/job/v1" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" - - ccipdeployment "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip" - "github.com/smartcontractkit/chainlink/integration-tests/deployment/memory" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func Test0002_InitialDeploy(t *testing.T) { lggr := logger.TestLogger(t) ctx := ccipdeployment.Context(t) - tenv := ccipdeployment.NewDeployedTestEnvironment(t, lggr) + tenv := ccipdeployment.NewEnvironmentWithCR(t, lggr, 3) e := tenv.Env nodes := tenv.Nodes chains := e.Chains @@ -38,7 +33,8 @@ func Test0002_InitialDeploy(t *testing.T) { // Apply migration output, err := Apply0002(tenv.Env, ccipdeployment.DeployCCIPContractConfig{ - HomeChainSel: tenv.HomeChainSel, + HomeChainSel: tenv.HomeChainSel, + ChainsToDeploy: tenv.Env.AllChainSelectors(), // Capreg/config already exist. CCIPOnChainState: state, }) @@ -48,7 +44,7 @@ func Test0002_InitialDeploy(t *testing.T) { require.NoError(t, err) // Ensure capreg logs are up to date. - require.NoError(t, ReplayAllLogs(nodes, chains)) + require.NoError(t, ccipdeployment.ReplayAllLogs(nodes, chains)) // Apply the jobs. for nodeID, jobs := range output.JobSpecs { @@ -67,9 +63,8 @@ func Test0002_InitialDeploy(t *testing.T) { time.Sleep(30 * time.Second) // Ensure job related logs are up to date. - require.NoError(t, ReplayAllLogs(nodes, chains)) + require.NoError(t, ccipdeployment.ReplayAllLogs(nodes, chains)) - // Send a request from every router // Add all lanes for source := range e.Chains { for dest := range e.Chains { @@ -80,47 +75,19 @@ func Test0002_InitialDeploy(t *testing.T) { } // Send a message from each chain to every other chain. - for src, srcChain := range e.Chains { + expectedSeqNum := make(map[uint64]uint64) + for src := range e.Chains { for dest := range e.Chains { if src == dest { continue } - msg := router.ClientEVM2AnyMessage{ - Receiver: common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32), - Data: []byte("hello"), - TokenAmounts: nil, // TODO: no tokens for now - FeeToken: state.Chains[src].Weth9.Address(), - ExtraArgs: nil, // TODO: no extra args for now, falls back to default - } - fee, err := state.Chains[src].Router.GetFee( - &bind.CallOpts{Context: context.Background()}, dest, msg) - require.NoError(t, err, deployment.MaybeDataErr(err)) - tx, err := state.Chains[src].Weth9.Deposit(&bind.TransactOpts{ - From: e.Chains[src].DeployerKey.From, - Signer: e.Chains[src].DeployerKey.Signer, - Value: fee, - }) - require.NoError(t, err) - _, err = srcChain.Confirm(tx) - require.NoError(t, err) - - // TODO: should be able to avoid this by using native? - tx, err = state.Chains[src].Weth9.Approve(e.Chains[src].DeployerKey, - state.Chains[src].Router.Address(), fee) - require.NoError(t, err) - _, err = srcChain.Confirm(tx) - require.NoError(t, err) - - t.Logf("Sending CCIP request from chain selector %d to chain selector %d", - src, dest) - tx, err = state.Chains[src].Router.CcipSend(e.Chains[src].DeployerKey, dest, msg) - require.NoError(t, err) - _, err = srcChain.Confirm(tx) - require.NoError(t, err) + seqNum := ccipdeployment.SendRequest(t, e, state, src, dest, false) + expectedSeqNum[dest] = seqNum } } // Wait for all commit reports to land. + cStart := time.Now() var wg sync.WaitGroup for src, srcChain := range e.Chains { for dest, dstChain := range e.Chains { @@ -132,11 +99,13 @@ func Test0002_InitialDeploy(t *testing.T) { wg.Add(1) go func(src, dest uint64) { defer wg.Done() - waitForCommitWithInterval(t, srcChain, dstChain, state.Chains[dest].EvmOffRampV160, ccipocr3.SeqNumRange{1, 1}) + waitForCommitWithInterval(t, srcChain, dstChain, state.Chains[dest].OffRamp, + ccipocr3.SeqNumRange{ccipocr3.SeqNum(expectedSeqNum[dest]), ccipocr3.SeqNum(expectedSeqNum[dest])}) }(src, dest) } } wg.Wait() + cEnd := time.Now() // Wait for all exec reports to land for src, srcChain := range e.Chains { @@ -149,26 +118,19 @@ func Test0002_InitialDeploy(t *testing.T) { wg.Add(1) go func(src, dest deployment.Chain) { defer wg.Done() - waitForExecWithSeqNr(t, src, dest, state.Chains[dest.Selector].EvmOffRampV160, 1) + ccipdeployment.ConfirmExecution(t, + src, dest, state.Chains[dest.Selector].OffRamp, + expectedSeqNum[dest.Selector]) }(srcChain, dstChain) } } wg.Wait() - + eEnd := time.Now() + t.Log("Commit time:", cEnd.Sub(cStart)) + t.Log("Exec time:", eEnd.Sub(cEnd)) // TODO: Apply the proposal. } -func ReplayAllLogs(nodes map[string]memory.Node, chains map[uint64]deployment.Chain) error { - for _, node := range nodes { - for sel := range chains { - if err := node.ReplayLogs(map[uint64]uint64{sel: 1}); err != nil { - return err - } - } - } - return nil -} - func waitForCommitWithInterval( t *testing.T, src deployment.Chain, @@ -211,34 +173,3 @@ func waitForCommitWithInterval( } } } - -func waitForExecWithSeqNr(t *testing.T, - source, dest deployment.Chain, - offramp *offramp.OffRamp, - expectedSeqNr uint64) { - tick := time.NewTicker(5 * time.Second) - defer tick.Stop() - for range tick.C { - // TODO: Clean this up - source.Client.(*backends.SimulatedBackend).Commit() - dest.Client.(*backends.SimulatedBackend).Commit() - scc, err := offramp.GetSourceChainConfig(nil, source.Selector) - require.NoError(t, err) - t.Logf("Waiting for ExecutionStateChanged on chain %d from chain %d with expected sequence number %d, current onchain minSeqNr: %d", - dest.Selector, source.Selector, expectedSeqNr, scc.MinSeqNr) - iter, err := offramp.FilterExecutionStateChanged(nil, - []uint64{source.Selector}, []uint64{expectedSeqNr}, nil) - require.NoError(t, err) - var count int - for iter.Next() { - if iter.Event.SequenceNumber == expectedSeqNr && iter.Event.SourceChainSelector == source.Selector { - count++ - } - } - if count == 1 { - t.Logf("Received ExecutionStateChanged on chain %d from chain %d with expected sequence number %d", - dest.Selector, source.Selector, expectedSeqNr) - return - } - } -} diff --git a/integration-tests/deployment/ccip/deploy.go b/integration-tests/deployment/ccip/deploy.go index eb2ddae2933..72ab5d7d6ee 100644 --- a/integration-tests/deployment/ccip/deploy.go +++ b/integration-tests/deployment/ccip/deploy.go @@ -1,20 +1,24 @@ package ccipdeployment import ( + "crypto/ecdsa" "fmt" "math/big" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" - owner_helpers "github.com/smartcontractkit/ccip-owner-contracts/gethwrappers" + "github.com/ethereum/go-ethereum/crypto" + "github.com/smartcontractkit/ccip-owner-contracts/tools/configwrappers" + owner_helpers "github.com/smartcontractkit/ccip-owner-contracts/tools/gethwrappers" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" "github.com/smartcontractkit/chainlink/integration-tests/deployment" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/maybe_revert_message_receiver" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/nonce_manager" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" @@ -36,16 +40,28 @@ var ( Router deployment.ContractType = "Router" TokenAdminRegistry deployment.ContractType = "TokenAdminRegistry" NonceManager deployment.ContractType = "NonceManager" - PriceRegistry deployment.ContractType = "PriceRegistry" + FeeQuoter deployment.ContractType = "FeeQuoter" ManyChainMultisig deployment.ContractType = "ManyChainMultiSig" CCIPConfig deployment.ContractType = "CCIPConfig" RBACTimelock deployment.ContractType = "RBACTimelock" OnRamp deployment.ContractType = "OnRamp" OffRamp deployment.ContractType = "OffRamp" - CCIPReceiver deployment.ContractType = "CCIPReceiver" CapabilitiesRegistry deployment.ContractType = "CapabilitiesRegistry" + // Note test router maps to a regular router contract. + TestRouter deployment.ContractType = "TestRouter" + CCIPReceiver deployment.ContractType = "CCIPReceiver" + + TestXXXMCMSSigner *ecdsa.PrivateKey ) +func init() { + key, err := crypto.GenerateKey() + if err != nil { + panic(err) + } + TestXXXMCMSSigner = key +} + type Contracts interface { *capabilities_registry.CapabilitiesRegistry | *rmn_proxy_contract.RMNProxyContract | @@ -101,7 +117,8 @@ func deployContract[C Contracts]( } type DeployCCIPContractConfig struct { - HomeChainSel uint64 + HomeChainSel uint64 + ChainsToDeploy []uint64 // Existing contracts which we want to skip deployment // Leave empty if we want to deploy everything // TODO: Add skips to deploy function. @@ -128,17 +145,23 @@ func DeployCCIPContracts(e deployment.Environment, c DeployCCIPContractConfig) ( e.Logger.Errorw("Failed to get hashed capability id", "err", err) return ab, err } + if cr != CCIPCapabilityID { + return ab, fmt.Errorf("Capability registry does not support CCIP %s %s", hexutil.Encode(cr[:]), hexutil.Encode(CCIPCapabilityID[:])) + } // Signal to CR that our nodes support CCIP capability. if err := AddNodes( c.Chains[c.HomeChainSel].CapabilityRegistry, e.Chains[c.HomeChainSel], - nodes.PeerIDs(c.HomeChainSel), // Doesn't actually matter which sel here - [][32]byte{cr}, + nodes.NonBootstraps().PeerIDs(), ); err != nil { return ab, err } - for _, chain := range e.Chains { + for _, chainSel := range c.ChainsToDeploy { + chain, ok := e.Chains[chainSel] + if !ok { + return ab, fmt.Errorf("Chain %d not found", chainSel) + } ab, err = DeployChainContracts(e, chain, ab) if err != nil { return ab, err @@ -153,47 +176,28 @@ func DeployCCIPContracts(e deployment.Environment, c DeployCCIPContractConfig) ( e.Logger.Errorw("Failed to load chain state", "err", err) return ab, err } - // Enable ramps on price registry/nonce manager - tx, err := chainState.PriceRegistry.ApplyAuthorizedCallerUpdates(chain.DeployerKey, fee_quoter.AuthorizedCallersAuthorizedCallerArgs{ - // TODO: We enable the deployer initially to set prices - AddedCallers: []common.Address{chainState.EvmOffRampV160.Address(), chain.DeployerKey.From}, - }) - if _, err := deployment.ConfirmIfNoError(chain, tx, err); err != nil { - e.Logger.Errorw("Failed to confirm price registry authorized caller update", "err", err) - return ab, err - } - - tx, err = chainState.NonceManager.ApplyAuthorizedCallerUpdates(chain.DeployerKey, nonce_manager.AuthorizedCallersAuthorizedCallerArgs{ - AddedCallers: []common.Address{chainState.EvmOffRampV160.Address(), chainState.EvmOnRampV160.Address()}, - }) - if _, err := deployment.ConfirmIfNoError(chain, tx, err); err != nil { - e.Logger.Errorw("Failed to update nonce manager with ramps", "err", err) - return ab, err - } + // TODO: Do we want to extract this? // Add chain config for each chain. - _, err = AddChainConfig(e.Logger, + _, err = AddChainConfig( + e.Logger, e.Chains[c.HomeChainSel], c.Chains[c.HomeChainSel].CCIPConfig, chain.Selector, - nodes.PeerIDs(chain.Selector), - uint8(len(nodes)/3)) + nodes.NonBootstraps().PeerIDs()) if err != nil { return ab, err } - // For each chain, we create a DON on the home chain. - if err := AddDON(e.Logger, - cr, + // For each chain, we create a DON on the home chain (2 OCR instances) + if err := AddDON( + e.Logger, c.Chains[c.HomeChainSel].CapabilityRegistry, c.Chains[c.HomeChainSel].CCIPConfig, - chainState.EvmOffRampV160, + chainState.OffRamp, chain, e.Chains[c.HomeChainSel], - uint8(len(nodes)/3), - nodes.BootstrapPeerIDs(chain.Selector)[0], - nodes.PeerIDs(chain.Selector), - nodes, + nodes.NonBootstraps(), ); err != nil { e.Logger.Errorw("Failed to add DON", "err", err) return ab, err @@ -203,7 +207,11 @@ func DeployCCIPContracts(e deployment.Environment, c DeployCCIPContractConfig) ( return ab, nil } -func DeployChainContracts(e deployment.Environment, chain deployment.Chain, ab deployment.AddressBook) (deployment.AddressBook, error) { +func DeployChainContracts( + e deployment.Environment, + chain deployment.Chain, + ab deployment.AddressBook, +) (deployment.AddressBook, error) { ccipReceiver, err := deployContract(e.Logger, chain, ab, func(chain deployment.Chain) ContractDeploy[*maybe_revert_message_receiver.MaybeRevertMessageReceiver] { receiverAddr, tx, receiver, err2 := maybe_revert_message_receiver.DeployMaybeRevertMessageReceiver( @@ -253,16 +261,37 @@ func DeployChainContracts(e deployment.Environment, chain deployment.Chain, ab d e.Logger.Errorw("Failed to deploy mcm", "err", err) return ab, err } - // TODO: Address soon + // TODO: Parameterize this. e.Logger.Infow("deployed mcm", "addr", mcm.Address) + publicKey := TestXXXMCMSSigner.Public().(*ecdsa.PublicKey) + // Convert the public key to an Ethereum address + address := crypto.PubkeyToAddress(*publicKey) + c, err := configwrappers.NewConfig(1, []common.Address{address}, []configwrappers.Config{}) + if err != nil { + e.Logger.Errorw("Failed to create config", "err", err) + return ab, err + } + groupQuorums, groupParents, signerAddresses, signerGroups := c.ExtractSetConfigInputs() + mcmsTx, err := mcm.Contract.SetConfig(chain.DeployerKey, + signerAddresses, + signerGroups, // Signer 1 is int group 0 (root group) with quorum 1. + groupQuorums, + groupParents, + false, + ) + if _, err := deployment.ConfirmIfNoError(chain, mcmsTx, err); err != nil { + e.Logger.Errorw("Failed to confirm mcm config", "err", err) + return ab, err + } - _, err = deployContract(e.Logger, chain, ab, + timelock, err := deployContract(e.Logger, chain, ab, func(chain deployment.Chain) ContractDeploy[*owner_helpers.RBACTimelock] { timelock, tx, cc, err2 := owner_helpers.DeployRBACTimelock( chain.DeployerKey, chain.Client, big.NewInt(0), // minDelay mcm.Address, + // TODO: Actual MCM groups need to be parameterized. []common.Address{mcm.Address}, // proposers []common.Address{chain.DeployerKey.From}, //executors []common.Address{mcm.Address}, // cancellers @@ -295,6 +324,8 @@ func DeployChainContracts(e deployment.Environment, chain deployment.Chain, ab d } e.Logger.Infow("deployed rmnProxy", "addr", rmnProxy.Address) + // TODO: Need general configuration for using pre-existing weth9 + // link tokens. weth9, err := deployContract(e.Logger, chain, ab, func(chain deployment.Chain) ContractDeploy[*weth9.WETH9] { weth9Addr, tx, weth9c, err2 := weth9.DeployWETH9( @@ -347,6 +378,24 @@ func DeployChainContracts(e deployment.Environment, chain deployment.Chain, ab d } e.Logger.Infow("deployed router", "addr", routerContract) + testRouterContract, err := deployContract(e.Logger, chain, ab, + func(chain deployment.Chain) ContractDeploy[*router.Router] { + routerAddr, tx, routerC, err2 := router.DeployRouter( + chain.DeployerKey, + chain.Client, + weth9.Address, + rmnProxy.Address, + ) + return ContractDeploy[*router.Router]{ + routerAddr, routerC, tx, deployment.NewTypeAndVersion(TestRouter, deployment.Version1_2_0), err2, + } + }) + if err != nil { + e.Logger.Errorw("Failed to deploy test router", "err", err) + return ab, err + } + e.Logger.Infow("deployed test router", "addr", testRouterContract.Address) + tokenAdminRegistry, err := deployContract(e.Logger, chain, ab, func(chain deployment.Chain) ContractDeploy[*token_admin_registry.TokenAdminRegistry] { tokenAdminRegistryAddr, tx, tokenAdminRegistry, err2 := token_admin_registry.DeployTokenAdminRegistry( @@ -388,7 +437,7 @@ func DeployChainContracts(e deployment.Environment, chain deployment.Chain, ab d LinkToken: linkToken.Address, StalenessThreshold: uint32(24 * 60 * 60), }, - []common.Address{}, // ramps added after + []common.Address{timelock.Address}, // timelock should be able to update, ramps added after []common.Address{weth9.Address, linkToken.Address}, // fee tokens []fee_quoter.FeeQuoterTokenPriceFeedUpdate{}, []fee_quoter.FeeQuoterTokenTransferFeeConfigArgs{}, // TODO: tokens @@ -405,11 +454,11 @@ func DeployChainContracts(e deployment.Environment, chain deployment.Chain, ab d []fee_quoter.FeeQuoterDestChainConfigArgs{}, ) return ContractDeploy[*fee_quoter.FeeQuoter]{ - prAddr, pr, tx, deployment.NewTypeAndVersion(PriceRegistry, deployment.Version1_6_0_dev), err2, + prAddr, pr, tx, deployment.NewTypeAndVersion(FeeQuoter, deployment.Version1_6_0_dev), err2, } }) if err != nil { - e.Logger.Errorw("Failed to deploy price registry", "err", err) + e.Logger.Errorw("Failed to deploy fee quoter", "err", err) return ab, err } @@ -468,5 +517,24 @@ func DeployChainContracts(e deployment.Environment, chain deployment.Chain, ab d return ab, err } e.Logger.Infow("deployed offramp", "addr", offRamp) + + // Basic wiring is always needed. + tx, err := feeQuoter.Contract.ApplyAuthorizedCallerUpdates(chain.DeployerKey, fee_quoter.AuthorizedCallersAuthorizedCallerArgs{ + // TODO: We enable the deployer initially to set prices + // Should be removed after. + AddedCallers: []common.Address{offRamp.Contract.Address(), chain.DeployerKey.From}, + }) + if _, err := deployment.ConfirmIfNoError(chain, tx, err); err != nil { + e.Logger.Errorw("Failed to confirm fee quoter authorized caller update", "err", err) + return ab, err + } + + tx, err = nonceManager.Contract.ApplyAuthorizedCallerUpdates(chain.DeployerKey, nonce_manager.AuthorizedCallersAuthorizedCallerArgs{ + AddedCallers: []common.Address{offRamp.Contract.Address(), onRamp.Contract.Address()}, + }) + if _, err := deployment.ConfirmIfNoError(chain, tx, err); err != nil { + e.Logger.Errorw("Failed to update nonce manager with ramps", "err", err) + return ab, err + } return ab, nil } diff --git a/integration-tests/deployment/ccip/deploy_home_chain.go b/integration-tests/deployment/ccip/deploy_home_chain.go index 1fe6bd5d562..ec078e4a9db 100644 --- a/integration-tests/deployment/ccip/deploy_home_chain.go +++ b/integration-tests/deployment/ccip/deploy_home_chain.go @@ -4,7 +4,7 @@ import ( "bytes" "context" "errors" - "sort" + "fmt" "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -17,9 +17,9 @@ import ( commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" - "github.com/smartcontractkit/chainlink/integration-tests/deployment" cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ocr3_config_encoder" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" @@ -52,6 +52,18 @@ const ( MaxDurationShouldTransmitAcceptedReport = 10 * time.Second ) +var ( + CCIPCapabilityID = utils.Keccak256Fixed(MustABIEncode(`[{"type": "string"}, {"type": "string"}]`, CapabilityLabelledName, CapabilityVersion)) +) + +func MustABIEncode(abiString string, args ...interface{}) []byte { + encoded, err := utils.ABIEncode(abiString, args...) + if err != nil { + panic(err) + } + return encoded +} + func DeployCapReg(lggr logger.Logger, chains map[uint64]deployment.Chain, chainSel uint64) (deployment.AddressBook, common.Address, error) { ab := deployment.NewMemoryAddressBook() chain := chains[chainSel] @@ -69,6 +81,7 @@ func DeployCapReg(lggr logger.Logger, chains map[uint64]deployment.Chain, chainS lggr.Errorw("Failed to deploy capreg", "err", err) return ab, common.Address{}, err } + lggr.Infow("deployed capreg", "addr", capReg.Address) ccipConfig, err := deployContract( lggr, chain, ab, @@ -115,27 +128,18 @@ func DeployCapReg(lggr logger.Logger, chains map[uint64]deployment.Chain, chainS return ab, capReg.Address, nil } -func sortP2PIDS(p2pIDs [][32]byte) { - sort.Slice(p2pIDs, func(i, j int) bool { - return bytes.Compare(p2pIDs[i][:], p2pIDs[j][:]) < 0 - }) -} - func AddNodes( capReg *capabilities_registry.CapabilitiesRegistry, chain deployment.Chain, p2pIDs [][32]byte, - capabilityIDs [][32]byte, ) error { - // Need to sort, otherwise _checkIsValidUniqueSubset onChain will fail - sortP2PIDS(p2pIDs) var nodeParams []capabilities_registry.CapabilitiesRegistryNodeParams for _, p2pID := range p2pIDs { nodeParam := capabilities_registry.CapabilitiesRegistryNodeParams{ NodeOperatorId: NodeOperatorID, Signer: p2pID, // Not used in tests P2pId: p2pID, - HashedCapabilityIds: capabilityIDs, + HashedCapabilityIds: [][32]byte{CCIPCapabilityID}, } nodeParams = append(nodeParams, nodeParam) } @@ -164,10 +168,7 @@ func AddChainConfig( ccipConfig *ccip_config.CCIPConfig, chainSelector uint64, p2pIDs [][32]byte, - f uint8, ) (ccip_config.CCIPConfigTypesChainConfigInfo, error) { - // Need to sort, otherwise _checkIsValidUniqueSubset onChain will fail - sortP2PIDS(p2pIDs) // First Add ChainConfig that includes all p2pIDs as readers encodedExtraChainConfig, err := chainconfig.EncodeChainConfig(chainconfig.ChainConfig{ GasPriceDeviationPPB: ccipocr3.NewBigIntFromInt64(1000), @@ -177,11 +178,10 @@ func AddChainConfig( if err != nil { return ccip_config.CCIPConfigTypesChainConfigInfo{}, err } - chainConfig := SetupConfigInfo(chainSelector, p2pIDs, f, encodedExtraChainConfig) - inputConfig := []ccip_config.CCIPConfigTypesChainConfigInfo{ + chainConfig := SetupConfigInfo(chainSelector, p2pIDs, uint8(len(p2pIDs)/3), encodedExtraChainConfig) + tx, err := ccipConfig.ApplyChainConfigUpdates(h.DeployerKey, nil, []ccip_config.CCIPConfigTypesChainConfigInfo{ chainConfig, - } - tx, err := ccipConfig.ApplyChainConfigUpdates(h.DeployerKey, nil, inputConfig) + }) if _, err := deployment.ConfirmIfNoError(h, tx, err); err != nil { return ccip_config.CCIPConfigTypesChainConfigInfo{}, err } @@ -189,20 +189,13 @@ func AddChainConfig( return chainConfig, nil } -func AddDON( +func BuildAddDONArgs( lggr logger.Logger, - ccipCapabilityID [32]byte, - capReg *capabilities_registry.CapabilitiesRegistry, - ccipConfig *ccip_config.CCIPConfig, offRamp *offramp.OffRamp, dest deployment.Chain, - home deployment.Chain, - f uint8, - bootstrapP2PID [32]byte, - p2pIDs [][32]byte, - nodes []deployment.Node, -) error { - sortP2PIDS(p2pIDs) + nodes deployment.Nodes, +) ([]byte, error) { + p2pIDs := nodes.PeerIDs() // Get OCR3 Config from helper var schedule []int var oracles []confighelper2.OracleIdentityExtra @@ -221,7 +214,7 @@ func AddDON( tabi, err := ocr3_config_encoder.IOCR3ConfigEncoderMetaData.GetAbi() if err != nil { - return err + return nil, err } // Add DON on capability registry contract @@ -246,7 +239,7 @@ func AddDON( }) } if err2 != nil { - return err2 + return nil, err2 } signers, transmitters, configF, _, offchainConfigVersion, offchainConfig, err2 := ocr3confighelper.ContractSetConfigArgsForTests( DeltaProgress, @@ -264,11 +257,11 @@ func AddDON( MaxDurationObservation, MaxDurationShouldAcceptAttestedReport, MaxDurationShouldTransmitAcceptedReport, - int(f), + int(nodes.DefaultF()), []byte{}, // empty OnChainConfig ) if err2 != nil { - return err2 + return nil, err2 } signersBytes := make([][]byte, len(signers)) @@ -280,7 +273,7 @@ func AddDON( for i, transmitter := range transmitters { parsed, err2 := common.ParseHexOrString(string(transmitter)) if err2 != nil { - return err2 + return nil, err2 } transmittersBytes[i] = parsed } @@ -298,77 +291,100 @@ func AddDON( }) } + // TODO: Can just use utils.ABIEncode directly here. encodedCall, err := tabi.Pack("exposeOCR3Config", ocr3Configs) if err != nil { - return err + return nil, err } // Trim first four bytes to remove function selector. encodedConfigs := encodedCall[4:] + return encodedConfigs, nil +} - tx, err := capReg.AddDON(home.DeployerKey, p2pIDs, []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: ccipCapabilityID, - Config: encodedConfigs, - }, - }, false, false, f) - if _, err := deployment.ConfirmIfNoError(home, tx, err); err != nil { - return err - } - - latestBlock, err := home.Client.HeaderByNumber(context.Background(), nil) +func LatestCCIPDON(registry *capabilities_registry.CapabilitiesRegistry) (*capabilities_registry.CapabilitiesRegistryDONInfo, error) { + dons, err := registry.GetDONs(nil) if err != nil { - return err + return nil, err } - endBlock := latestBlock.Number.Uint64() - iter, err := capReg.FilterConfigSet(&bind.FilterOpts{ - Start: endBlock - 1, - End: &endBlock, - }, []uint32{}) - if err != nil { - return err - } - var donID uint32 - for iter.Next() { - donID = iter.Event.DonId - break - } - if donID == 0 { - return errors.New("failed to get donID") - } - - var signerAddresses []common.Address - for _, oracle := range oracles { - signerAddresses = append(signerAddresses, common.BytesToAddress(oracle.OnchainPublicKey)) - } - - var transmitterAddresses []common.Address - for _, oracle := range oracles { - transmitterAddresses = append(transmitterAddresses, common.HexToAddress(string(oracle.TransmitAccount))) + var ccipDON capabilities_registry.CapabilitiesRegistryDONInfo + for _, don := range dons { + if len(don.CapabilityConfigurations) == 1 && + don.CapabilityConfigurations[0].CapabilityId == CCIPCapabilityID && + don.Id > ccipDON.Id { + ccipDON = don + } } + return &ccipDON, nil +} - // get the config digest from the ccip config contract and set config on the offramp. +func BuildSetOCR3ConfigArgs( + donID uint32, + ccipConfig *ccip_config.CCIPConfig, +) ([]offramp.MultiOCR3BaseOCRConfigArgs, error) { var offrampOCR3Configs []offramp.MultiOCR3BaseOCRConfigArgs for _, pluginType := range []cctypes.PluginType{cctypes.PluginTypeCCIPCommit, cctypes.PluginTypeCCIPExec} { ocrConfig, err2 := ccipConfig.GetOCRConfig(&bind.CallOpts{ Context: context.Background(), }, donID, uint8(pluginType)) if err2 != nil { - return err2 + return nil, err2 } if len(ocrConfig) != 1 { - return errors.New("expected exactly one OCR3 config") + return nil, errors.New("expected exactly one OCR3 config") + } + var signerAddresses []common.Address + for _, signer := range ocrConfig[0].Config.Signers { + signerAddresses = append(signerAddresses, common.BytesToAddress(signer)) + } + + var transmitterAddresses []common.Address + for _, transmitter := range ocrConfig[0].Config.Transmitters { + transmitterAddresses = append(transmitterAddresses, common.BytesToAddress(transmitter)) } offrampOCR3Configs = append(offrampOCR3Configs, offramp.MultiOCR3BaseOCRConfigArgs{ ConfigDigest: ocrConfig[0].ConfigDigest, OcrPluginType: uint8(pluginType), - F: f, + F: ocrConfig[0].Config.F, IsSignatureVerificationEnabled: pluginType == cctypes.PluginTypeCCIPCommit, Signers: signerAddresses, Transmitters: transmitterAddresses, }) } + return offrampOCR3Configs, nil +} + +func AddDON( + lggr logger.Logger, + capReg *capabilities_registry.CapabilitiesRegistry, + ccipConfig *ccip_config.CCIPConfig, + offRamp *offramp.OffRamp, + dest deployment.Chain, + home deployment.Chain, + nodes deployment.Nodes, +) error { + encodedConfigs, err := BuildAddDONArgs(lggr, offRamp, dest, nodes) + if err != nil { + return err + } + tx, err := capReg.AddDON(home.DeployerKey, nodes.PeerIDs(), []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ + { + CapabilityId: CCIPCapabilityID, + Config: encodedConfigs, + }, + }, false, false, nodes.DefaultF()) + if _, err := deployment.ConfirmIfNoError(home, tx, err); err != nil { + return err + } + don, err := LatestCCIPDON(capReg) + if err != nil { + return err + } + offrampOCR3Configs, err := BuildSetOCR3ConfigArgs(don.Id, ccipConfig) + if err != nil { + return err + } tx, err = offRamp.SetOCR3Configs(dest.DeployerKey, offrampOCR3Configs) if _, err := deployment.ConfirmIfNoError(dest, tx, err); err != nil { @@ -376,25 +392,37 @@ func AddDON( } for _, pluginType := range []cctypes.PluginType{cctypes.PluginTypeCCIPCommit, cctypes.PluginTypeCCIPExec} { - _, err = offRamp.LatestConfigDetails(&bind.CallOpts{ + ocrConfig, err := offRamp.LatestConfigDetails(&bind.CallOpts{ Context: context.Background(), }, uint8(pluginType)) if err != nil { - //return err - return deployment.MaybeDataErr(err) + return err } // TODO: assertions to be done as part of full state // resprentation validation CCIP-3047 - //require.Equalf(t, offrampOCR3Configs[pluginType].ConfigDigest, ocrConfig.ConfigInfo.ConfigDigest, "%s OCR3 config digest mismatch", pluginType.String()) - //require.Equalf(t, offrampOCR3Configs[pluginType].F, ocrConfig.ConfigInfo.F, "%s OCR3 config F mismatch", pluginType.String()) - //require.Equalf(t, offrampOCR3Configs[pluginType].IsSignatureVerificationEnabled, ocrConfig.ConfigInfo.IsSignatureVerificationEnabled, "%s OCR3 config signature verification mismatch", pluginType.String()) - //if pluginType == cctypes.PluginTypeCCIPCommit { - // // only commit will set signers, exec doesn't need them. - // require.Equalf(t, offrampOCR3Configs[pluginType].Signers, ocrConfig.Signers, "%s OCR3 config signers mismatch", pluginType.String()) - //} - //require.Equalf(t, offrampOCR3Configs[pluginType].TransmittersByEVMChainID, ocrConfig.TransmittersByEVMChainID, "%s OCR3 config transmitters mismatch", pluginType.String()) + if offrampOCR3Configs[pluginType].ConfigDigest != ocrConfig.ConfigInfo.ConfigDigest { + return fmt.Errorf("%s OCR3 config digest mismatch", pluginType.String()) + } + if offrampOCR3Configs[pluginType].F != ocrConfig.ConfigInfo.F { + return fmt.Errorf("%s OCR3 config F mismatch", pluginType.String()) + } + if offrampOCR3Configs[pluginType].IsSignatureVerificationEnabled != ocrConfig.ConfigInfo.IsSignatureVerificationEnabled { + return fmt.Errorf("%s OCR3 config signature verification mismatch", pluginType.String()) + } + if pluginType == cctypes.PluginTypeCCIPCommit { + // only commit will set signers, exec doesn't need them. + for i, signer := range offrampOCR3Configs[pluginType].Signers { + if !bytes.Equal(signer.Bytes(), ocrConfig.Signers[i].Bytes()) { + return fmt.Errorf("%s OCR3 config signer mismatch", pluginType.String()) + } + } + } + for i, transmitter := range offrampOCR3Configs[pluginType].Transmitters { + if !bytes.Equal(transmitter.Bytes(), ocrConfig.Transmitters[i].Bytes()) { + return fmt.Errorf("%s OCR3 config transmitter mismatch", pluginType.String()) + } + } } - lggr.Infof("set ocr3 config on the offramp, signers: %+v, transmitters: %+v", signerAddresses, transmitterAddresses) return nil } diff --git a/integration-tests/deployment/ccip/deploy_test.go b/integration-tests/deployment/ccip/deploy_test.go index 7bc56f82f76..e2963b84a3b 100644 --- a/integration-tests/deployment/ccip/deploy_test.go +++ b/integration-tests/deployment/ccip/deploy_test.go @@ -28,6 +28,7 @@ func TestDeployCCIPContracts(t *testing.T) { require.NoError(t, err) ab, err := DeployCCIPContracts(e, DeployCCIPContractConfig{ HomeChainSel: homeChain, + ChainsToDeploy: e.AllChainSelectors(), CCIPOnChainState: s, }) require.NoError(t, err) diff --git a/integration-tests/deployment/ccip/jobs.go b/integration-tests/deployment/ccip/jobs.go index c46ab7270f6..49fb1e95422 100644 --- a/integration-tests/deployment/ccip/jobs.go +++ b/integration-tests/deployment/ccip/jobs.go @@ -1,11 +1,7 @@ package ccipdeployment import ( - "context" - "fmt" - "github.com/smartcontractkit/chainlink/integration-tests/deployment" - nodev1 "github.com/smartcontractkit/chainlink/integration-tests/deployment/jd/node/v1" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/validate" "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) @@ -13,67 +9,49 @@ import ( // In our case, the only address needed is the cap registry which is actually an env var. // and will pre-exist for our deployment. So the job specs only depend on the environment operators. func NewCCIPJobSpecs(nodeIds []string, oc deployment.OffchainClient) (map[string][]string, error) { + nodes, err := deployment.NodeInfo(nodeIds, oc) + if err != nil { + return nil, err + } // Generate a set of brand new job specs for CCIP for a specific environment // (including NOPs) and new addresses. // We want to assign one CCIP capability job to each node. And node with // an addr we'll list as bootstrapper. // Find the bootstrap nodes - bootstrapMp := make(map[string]struct{}) - for _, node := range nodeIds { - // TODO: Filter should accept multiple nodes - nodeChainConfigs, err := oc.ListNodeChainConfigs(context.Background(), &nodev1.ListNodeChainConfigsRequest{Filter: &nodev1.ListNodeChainConfigsRequest_Filter{ - NodeIds: []string{node}, - }}) - if err != nil { - return nil, err - } - for _, chainConfig := range nodeChainConfigs.ChainConfigs { - if chainConfig.Ocr2Config.IsBootstrap { - bootstrapMp[fmt.Sprintf("%s@%s", - // p2p_12D3... -> 12D3... - chainConfig.Ocr2Config.P2PKeyBundle.PeerId[4:], chainConfig.Ocr2Config.Multiaddr)] = struct{}{} - } - } - } - var bootstraps []string - for b := range bootstrapMp { - bootstraps = append(bootstraps, b) - } - nodesToJobSpecs := make(map[string][]string) - for _, node := range nodeIds { - // TODO: Filter should accept multiple. - nodeChainConfigs, err := oc.ListNodeChainConfigs(context.Background(), &nodev1.ListNodeChainConfigsRequest{Filter: &nodev1.ListNodeChainConfigsRequest_Filter{ - NodeIds: []string{node}, - }}) - if err != nil { - return nil, err - } - // only set P2PV2Bootstrappers in the job spec if the node is a plugin node. - var p2pV2Bootstrappers []string - for _, chainConfig := range nodeChainConfigs.ChainConfigs { - if !chainConfig.Ocr2Config.IsBootstrap { - p2pV2Bootstrappers = bootstraps - break - } + nodesToJobSpecs := make(map[string][]string) + for _, node := range nodes { + var spec string + var err error + if !node.IsBootstrap { + spec, err = validate.NewCCIPSpecToml(validate.SpecArgs{ + P2PV2Bootstrappers: nodes.BootstrapLocators(), + CapabilityVersion: CapabilityVersion, + CapabilityLabelledName: CapabilityLabelledName, + OCRKeyBundleIDs: map[string]string{ + // TODO: Validate that that all EVM chains are using the same keybundle. + relay.NetworkEVM: node.FirstOCRKeybundle().KeyBundleID, + }, + P2PKeyID: node.PeerID.String(), + RelayConfigs: nil, + PluginConfig: map[string]any{}, + }) + } else { + spec, err = validate.NewCCIPSpecToml(validate.SpecArgs{ + P2PV2Bootstrappers: []string{}, // Intentionally empty for bootstraps. + CapabilityVersion: CapabilityVersion, + CapabilityLabelledName: CapabilityLabelledName, + OCRKeyBundleIDs: map[string]string{}, + // TODO: validate that all EVM chains are using the same keybundle + P2PKeyID: node.PeerID.String(), + RelayConfigs: nil, + PluginConfig: map[string]any{}, + }) } - spec, err := validate.NewCCIPSpecToml(validate.SpecArgs{ - P2PV2Bootstrappers: p2pV2Bootstrappers, - CapabilityVersion: CapabilityVersion, - CapabilityLabelledName: CapabilityLabelledName, - OCRKeyBundleIDs: map[string]string{ - // TODO: Validate that that all EVM chains are using the same keybundle. - relay.NetworkEVM: nodeChainConfigs.ChainConfigs[0].Ocr2Config.OcrKeyBundle.BundleId, - }, - // TODO: validate that all EVM chains are using the same keybundle - P2PKeyID: nodeChainConfigs.ChainConfigs[0].Ocr2Config.P2PKeyBundle.PeerId, - RelayConfigs: nil, - PluginConfig: map[string]any{}, - }) if err != nil { return nil, err } - nodesToJobSpecs[node] = append(nodesToJobSpecs[node], spec) + nodesToJobSpecs[node.NodeID] = append(nodesToJobSpecs[node.NodeID], spec) } return nodesToJobSpecs, nil } diff --git a/integration-tests/deployment/ccip/propose.go b/integration-tests/deployment/ccip/propose.go index 4fc38965eaa..eced93dde0f 100644 --- a/integration-tests/deployment/ccip/propose.go +++ b/integration-tests/deployment/ccip/propose.go @@ -1,14 +1,20 @@ package ccipdeployment import ( + "bytes" + "context" "math/big" - "time" + "testing" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - owner_helpers "github.com/smartcontractkit/ccip-owner-contracts/gethwrappers" + "github.com/ethereum/go-ethereum/crypto" + owner_helpers "github.com/smartcontractkit/ccip-owner-contracts/tools/gethwrappers" + "github.com/smartcontractkit/ccip-owner-contracts/tools/proposal/mcms" + "github.com/smartcontractkit/ccip-owner-contracts/tools/proposal/timelock" chainsel "github.com/smartcontractkit/chain-selectors" + "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink/integration-tests/deployment" ) @@ -17,48 +23,160 @@ import ( func SimTransactOpts() *bind.TransactOpts { return &bind.TransactOpts{Signer: func(address common.Address, transaction *types.Transaction) (*types.Transaction, error) { return transaction, nil - }, From: common.HexToAddress("0x0"), NoSend: true, GasLimit: 200_000} + }, From: common.HexToAddress("0x0"), NoSend: true, GasLimit: 1_000_000} +} + +func SignProposal(t *testing.T, env deployment.Environment, proposal *timelock.MCMSWithTimelockProposal) *mcms.Executor { + executorClients := make(map[mcms.ChainIdentifier]mcms.ContractDeployBackend) + for _, chain := range env.Chains { + chainselc, exists := chainsel.ChainBySelector(chain.Selector) + require.True(t, exists) + chainSel := mcms.ChainIdentifier(chainselc.Selector) + executorClients[chainSel] = chain.Client + } + realProposal, err := proposal.ToMCMSOnlyProposal() + require.NoError(t, err) + executor, err := realProposal.ToExecutor(executorClients) + require.NoError(t, err) + payload, err := executor.SigningHash() + require.NoError(t, err) + // Sign the payload + sig, err := crypto.Sign(payload.Bytes(), TestXXXMCMSSigner) + require.NoError(t, err) + mcmSig, err := mcms.NewSignatureFromBytes(sig) + require.NoError(t, err) + executor.Proposal.Signatures = append(executor.Proposal.Signatures, mcmSig) + require.NoError(t, executor.Proposal.Validate()) + return executor +} + +func ExecuteProposal(t *testing.T, env deployment.Environment, executor *mcms.Executor, + state CCIPOnChainState, sel uint64) { + // Set the root. + tx, err2 := executor.SetRootOnChain(env.Chains[sel].DeployerKey, mcms.ChainIdentifier(sel)) + require.NoError(t, err2) + _, err2 = env.Chains[sel].Confirm(tx) + require.NoError(t, err2) + + // TODO: This sort of helper probably should move to the MCMS lib. + // Execute all the transactions in the proposal which are for this chain. + for _, chainOp := range executor.Operations[mcms.ChainIdentifier(sel)] { + for idx, op := range executor.ChainAgnosticOps { + if bytes.Equal(op.Data, chainOp.Data) && op.To == chainOp.To { + opTx, err3 := executor.ExecuteOnChain(env.Chains[sel].DeployerKey, idx) + require.NoError(t, err3) + block, err3 := env.Chains[sel].Confirm(opTx) + require.NoError(t, err3) + t.Log("executed", chainOp) + it, err3 := state.Chains[sel].Timelock.FilterCallScheduled(&bind.FilterOpts{ + Start: block, + End: &block, + Context: context.Background(), + }, nil, nil) + require.NoError(t, err3) + var calls []owner_helpers.RBACTimelockCall + var pred, salt [32]byte + for it.Next() { + // Note these are the same for the whole batch, can overwrite + pred = it.Event.Predecessor + salt = it.Event.Salt + t.Log("scheduled", it.Event) + calls = append(calls, owner_helpers.RBACTimelockCall{ + Target: it.Event.Target, + Data: it.Event.Data, + Value: it.Event.Value, + }) + } + tx, err := state.Chains[sel].Timelock.ExecuteBatch( + env.Chains[sel].DeployerKey, calls, pred, salt) + require.NoError(t, err) + _, err = env.Chains[sel].Confirm(tx) + require.NoError(t, err) + } + } + } } func GenerateAcceptOwnershipProposal( - e deployment.Environment, + state CCIPOnChainState, + homeChain uint64, chains []uint64, - ab deployment.AddressBook, -) (deployment.Proposal, error) { - state, err := LoadOnchainState(e, ab) - if err != nil { - return deployment.Proposal{}, err - } - // TODO: Just onramp as an example - var ops []owner_helpers.ManyChainMultiSigOp +) (*timelock.MCMSWithTimelockProposal, error) { + // TODO: Accept rest of contracts + var batches []timelock.BatchChainOperation + metaDataPerChain := make(map[mcms.ChainIdentifier]timelock.MCMSWithTimelockChainMetadata) for _, sel := range chains { - opCount, err := state.Chains[sel].Mcm.GetOpCount(nil) + chain, _ := chainsel.ChainBySelector(sel) + acceptOnRamp, err := state.Chains[sel].OnRamp.AcceptOwnership(SimTransactOpts()) if err != nil { - return deployment.Proposal{}, err + return nil, err } - - txData, err := state.Chains[sel].EvmOnRampV160.AcceptOwnership(SimTransactOpts()) + acceptFeeQuoter, err := state.Chains[sel].FeeQuoter.AcceptOwnership(SimTransactOpts()) if err != nil { - return deployment.Proposal{}, err + return nil, err } - evmID, err := chainsel.ChainIdFromSelector(sel) - if err != nil { - return deployment.Proposal{}, err + chainSel := mcms.ChainIdentifier(chain.Selector) + metaDataPerChain[chainSel] = timelock.MCMSWithTimelockChainMetadata{ + ChainMetadata: mcms.ChainMetadata{ + NonceOffset: 0, + MCMAddress: state.Chains[sel].Mcm.Address(), + }, + TimelockAddress: state.Chains[sel].Timelock.Address(), } - ops = append(ops, owner_helpers.ManyChainMultiSigOp{ - ChainId: big.NewInt(int64(evmID)), - MultiSig: state.Chains[sel].McmsAddr, - Nonce: opCount, - To: state.Chains[sel].EvmOnRampV160.Address(), - Value: big.NewInt(0), - Data: txData.Data(), + batches = append(batches, timelock.BatchChainOperation{ + ChainIdentifier: chainSel, + Batch: []mcms.Operation{ + { + To: state.Chains[sel].OnRamp.Address(), + Data: acceptOnRamp.Data(), + Value: big.NewInt(0), + }, + { + To: state.Chains[sel].FeeQuoter.Address(), + Data: acceptFeeQuoter.Data(), + Value: big.NewInt(0), + }, + }, }) } - // TODO: Real valid until. - return deployment.Proposal{ValidUntil: uint32(time.Now().Unix()), Ops: ops}, nil -} - -func ApplyProposal(env deployment.Environment, p deployment.Proposal, state CCIPOnChainState) error { - // TODO - return nil + acceptCR, err := state.Chains[homeChain].CapabilityRegistry.AcceptOwnership(SimTransactOpts()) + if err != nil { + return nil, err + } + acceptCCIPConfig, err := state.Chains[homeChain].CCIPConfig.AcceptOwnership(SimTransactOpts()) + if err != nil { + return nil, err + } + homeChainID := mcms.ChainIdentifier(homeChain) + metaDataPerChain[homeChainID] = timelock.MCMSWithTimelockChainMetadata{ + ChainMetadata: mcms.ChainMetadata{ + NonceOffset: 0, + MCMAddress: state.Chains[homeChain].Mcm.Address(), + }, + TimelockAddress: state.Chains[homeChain].Timelock.Address(), + } + batches = append(batches, timelock.BatchChainOperation{ + ChainIdentifier: homeChainID, + Batch: []mcms.Operation{ + { + To: state.Chains[homeChain].CapabilityRegistry.Address(), + Data: acceptCR.Data(), + Value: big.NewInt(0), + }, + { + To: state.Chains[homeChain].CCIPConfig.Address(), + Data: acceptCCIPConfig.Data(), + Value: big.NewInt(0), + }, + }, + }) + return timelock.NewMCMSWithTimelockProposal( + "1", + 2004259681, // TODO + []mcms.Signature{}, + false, + metaDataPerChain, + "blah", // TODO + batches, + timelock.Schedule, "0s") } diff --git a/integration-tests/deployment/ccip/state.go b/integration-tests/deployment/ccip/state.go index f129650b30b..50ed396d9d8 100644 --- a/integration-tests/deployment/ccip/state.go +++ b/integration-tests/deployment/ccip/state.go @@ -7,13 +7,15 @@ import ( "github.com/pkg/errors" chainsel "github.com/smartcontractkit/chain-selectors" - owner_wrappers "github.com/smartcontractkit/ccip-owner-contracts/gethwrappers" - "github.com/smartcontractkit/chainlink/integration-tests/deployment" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/maybe_revert_message_receiver" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" + + owner_wrappers "github.com/smartcontractkit/ccip-owner-contracts/tools/gethwrappers" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/nonce_manager" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" @@ -22,14 +24,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/token_admin_registry" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/weth9" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" ) type CCIPChainState struct { - EvmOnRampV160 *onramp.OnRamp - EvmOffRampV160 *offramp.OffRamp - PriceRegistry *fee_quoter.FeeQuoter + OnRamp *onramp.OnRamp + OffRamp *offramp.OffRamp + FeeQuoter *fee_quoter.FeeQuoter ArmProxy *rmn_proxy_contract.RMNProxyContract NonceManager *nonce_manager.NonceManager TokenAdminRegistry *token_admin_registry.TokenAdminRegistry @@ -42,12 +42,11 @@ type CCIPChainState struct { CapabilityRegistry *capabilities_registry.CapabilitiesRegistry CCIPConfig *ccip_config.CCIPConfig Mcm *owner_wrappers.ManyChainMultiSig - // TODO: remove once we have Address() on wrappers - McmsAddr common.Address - Timelock *owner_wrappers.RBACTimelock + Timelock *owner_wrappers.RBACTimelock // Test contracts - Receiver *maybe_revert_message_receiver.MaybeRevertMessageReceiver + Receiver *maybe_revert_message_receiver.MaybeRevertMessageReceiver + TestRouter *router.Router } // Onchain state always derivable from an address book. @@ -140,6 +139,24 @@ func (s CCIPOnChainState) Snapshot(chains []uint64) (CCIPSnapShot, error) { AuthorizedCallers: authorizedCallers, } } + if nm != nil { + authorizedCallers, err := nm.GetAllAuthorizedCallers(nil) + if err != nil { + return snapshot, err + } + tv, err := nm.TypeAndVersion(nil) + if err != nil { + return snapshot, err + } + c.NonceManager = NonceManagerView{ + Contract: Contract{ + TypeAndVersion: tv, + Address: nm.Address(), + }, + // TODO: these can be resolved using an address book + AuthorizedCallers: authorizedCallers, + } + } snapshot.Chains[chainName] = c } return snapshot, nil @@ -189,7 +206,6 @@ func LoadChainState(chain deployment.Chain, addresses map[string]deployment.Type return state, err } state.Mcm = mcms - state.McmsAddr = common.HexToAddress(address) case deployment.NewTypeAndVersion(CapabilitiesRegistry, deployment.Version1_0_0).String(): cr, err := capabilities_registry.NewCapabilitiesRegistry(common.HexToAddress(address), chain.Client) if err != nil { @@ -201,13 +217,13 @@ func LoadChainState(chain deployment.Chain, addresses map[string]deployment.Type if err != nil { return state, err } - state.EvmOnRampV160 = onRampC + state.OnRamp = onRampC case deployment.NewTypeAndVersion(OffRamp, deployment.Version1_6_0_dev).String(): offRamp, err := offramp.NewOffRamp(common.HexToAddress(address), chain.Client) if err != nil { return state, err } - state.EvmOffRampV160 = offRamp + state.OffRamp = offRamp case deployment.NewTypeAndVersion(ARMProxy, deployment.Version1_0_0).String(): armProxy, err := rmn_proxy_contract.NewRMNProxyContract(common.HexToAddress(address), chain.Client) if err != nil { @@ -244,12 +260,18 @@ func LoadChainState(chain deployment.Chain, addresses map[string]deployment.Type return state, err } state.Router = r - case deployment.NewTypeAndVersion(PriceRegistry, deployment.Version1_6_0_dev).String(): - pr, err := fee_quoter.NewFeeQuoter(common.HexToAddress(address), chain.Client) + case deployment.NewTypeAndVersion(TestRouter, deployment.Version1_2_0).String(): + r, err := router.NewRouter(common.HexToAddress(address), chain.Client) + if err != nil { + return state, err + } + state.TestRouter = r + case deployment.NewTypeAndVersion(FeeQuoter, deployment.Version1_6_0_dev).String(): + fq, err := fee_quoter.NewFeeQuoter(common.HexToAddress(address), chain.Client) if err != nil { return state, err } - state.PriceRegistry = pr + state.FeeQuoter = fq case deployment.NewTypeAndVersion(LinkToken, deployment.Version1_0_0).String(): lt, err := burn_mint_erc677.NewBurnMintERC677(common.HexToAddress(address), chain.Client) if err != nil { diff --git a/integration-tests/deployment/ccip/test_helpers.go b/integration-tests/deployment/ccip/test_helpers.go index 2ec837c9eec..779b29a7496 100644 --- a/integration-tests/deployment/ccip/test_helpers.go +++ b/integration-tests/deployment/ccip/test_helpers.go @@ -2,12 +2,21 @@ package ccipdeployment import ( "context" + "sort" "testing" + "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/common" chainsel "github.com/smartcontractkit/chain-selectors" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + jobv1 "github.com/smartcontractkit/chainlink/integration-tests/deployment/jd/job/v1" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" + "github.com/smartcontractkit/chainlink/integration-tests/deployment" "github.com/smartcontractkit/chainlink/integration-tests/deployment/memory" @@ -40,17 +49,21 @@ type DeployedTestEnvironment struct { // NewDeployedEnvironment creates a new CCIP environment // with capreg and nodes set up. -func NewDeployedTestEnvironment(t *testing.T, lggr logger.Logger) DeployedTestEnvironment { +func NewEnvironmentWithCR(t *testing.T, lggr logger.Logger, numChains int) DeployedTestEnvironment { ctx := Context(t) - chains := memory.NewMemoryChains(t, 3) - homeChainSel := uint64(0) - homeChainEVM := uint64(0) + chains := memory.NewMemoryChains(t, numChains) + // Lower chainSel is home chain. + var chainSels []uint64 // Say first chain is home chain. for chainSel := range chains { - homeChainEVM, _ = chainsel.ChainIdFromSelector(chainSel) - homeChainSel = chainSel - break + chainSels = append(chainSels, chainSel) } + sort.Slice(chainSels, func(i, j int) bool { + return chainSels[i] < chainSels[j] + }) + // Take lowest for determinism. + homeChainSel := chainSels[0] + homeChainEVM, _ := chainsel.ChainIdFromSelector(homeChainSel) ab, capReg, err := DeployCapReg(lggr, chains, homeChainSel) require.NoError(t, err) @@ -73,3 +86,107 @@ func NewDeployedTestEnvironment(t *testing.T, lggr logger.Logger) DeployedTestEn Nodes: nodes, } } + +func NewEnvironmentWithCRAndJobs(t *testing.T, lggr logger.Logger, numChains int) DeployedTestEnvironment { + ctx := Context(t) + e := NewEnvironmentWithCR(t, lggr, numChains) + jbs, err := NewCCIPJobSpecs(e.Env.NodeIDs, e.Env.Offchain) + require.NoError(t, err) + for nodeID, jobs := range jbs { + for _, job := range jobs { + // Note these auto-accept + _, err := e.Env.Offchain.ProposeJob(ctx, + &jobv1.ProposeJobRequest{ + NodeId: nodeID, + Spec: job, + }) + require.NoError(t, err) + } + } + // Wait for plugins to register filters? + // TODO: Investigate how to avoid. + time.Sleep(30 * time.Second) + + // Ensure job related logs are up to date. + require.NoError(t, ReplayAllLogs(e.Nodes, e.Env.Chains)) + return e +} + +func ReplayAllLogs(nodes map[string]memory.Node, chains map[uint64]deployment.Chain) error { + for _, node := range nodes { + for sel := range chains { + if err := node.ReplayLogs(map[uint64]uint64{sel: 1}); err != nil { + return err + } + } + } + return nil +} + +func SendRequest(t *testing.T, e deployment.Environment, state CCIPOnChainState, src, dest uint64, testRouter bool) uint64 { + msg := router.ClientEVM2AnyMessage{ + Receiver: common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32), + Data: []byte("hello"), + TokenAmounts: nil, // TODO: no tokens for now + // Pay native. + FeeToken: common.HexToAddress("0x0"), + ExtraArgs: nil, // TODO: no extra args for now, falls back to default + } + router := state.Chains[src].Router + if testRouter { + router = state.Chains[src].TestRouter + } + fee, err := router.GetFee( + &bind.CallOpts{Context: context.Background()}, dest, msg) + require.NoError(t, err, deployment.MaybeDataErr(err)) + + t.Logf("Sending CCIP request from chain selector %d to chain selector %d", + src, dest) + e.Chains[src].DeployerKey.Value = fee + tx, err := router.CcipSend( + e.Chains[src].DeployerKey, + dest, + msg) + require.NoError(t, err) + blockNum, err := e.Chains[src].Confirm(tx) + require.NoError(t, err) + it, err := state.Chains[src].OnRamp.FilterCCIPMessageSent(&bind.FilterOpts{ + Start: blockNum, + End: &blockNum, + Context: context.Background(), + }, []uint64{dest}) + require.NoError(t, err) + require.True(t, it.Next()) + return it.Event.Message.Header.SequenceNumber +} + +func ConfirmExecution(t *testing.T, + source, dest deployment.Chain, + offramp *offramp.OffRamp, + expectedSeqNr uint64) { + tick := time.NewTicker(5 * time.Second) + defer tick.Stop() + for range tick.C { + // TODO: Clean this up + source.Client.(*backends.SimulatedBackend).Commit() + dest.Client.(*backends.SimulatedBackend).Commit() + scc, err := offramp.GetSourceChainConfig(nil, source.Selector) + require.NoError(t, err) + t.Logf("Waiting for ExecutionStateChanged on chain %d from chain %d with expected sequence number %d, current onchain minSeqNr: %d", + dest.Selector, source.Selector, expectedSeqNr, scc.MinSeqNr) + iter, err := offramp.FilterExecutionStateChanged(nil, + []uint64{source.Selector}, []uint64{expectedSeqNr}, nil) + require.NoError(t, err) + var count int + for iter.Next() { + if iter.Event.SequenceNumber == expectedSeqNr && iter.Event.SourceChainSelector == source.Selector { + count++ + } + } + if count == 1 { + t.Logf("Received ExecutionStateChanged on chain %d from chain %d with expected sequence number %d", + dest.Selector, source.Selector, expectedSeqNr) + return + } + } +} diff --git a/integration-tests/deployment/changeset.go b/integration-tests/deployment/changeset.go index d929022ed96..aeac3e8e722 100644 --- a/integration-tests/deployment/changeset.go +++ b/integration-tests/deployment/changeset.go @@ -1,28 +1,12 @@ package deployment import ( - owner_wrappers "github.com/smartcontractkit/ccip-owner-contracts/gethwrappers" + "github.com/smartcontractkit/ccip-owner-contracts/tools/proposal/timelock" ) -// TODO: Move to real MCM structs once available. -type Proposal struct { - // keccak256(abi.encode(root, validUntil)) is what is signed by MCMS - // signers. - ValidUntil uint32 - // Leaves are the items in the proposal. - // Uses these to generate the root as well as display whats in the root. - // These Ops may be destined for distinct chains. - Ops []owner_wrappers.ManyChainMultiSigOp -} - -func (p Proposal) String() string { - // TODO - return "" -} - // Services as input to CI/Async tasks type ChangesetOutput struct { JobSpecs map[string][]string - Proposals []Proposal + Proposals []timelock.MCMSWithTimelockProposal AddressBook AddressBook } diff --git a/integration-tests/deployment/environment.go b/integration-tests/deployment/environment.go index 5dfa1cd24e4..692d7744b12 100644 --- a/integration-tests/deployment/environment.go +++ b/integration-tests/deployment/environment.go @@ -1,10 +1,12 @@ package deployment import ( + "bytes" "context" "errors" "fmt" "math/big" + "sort" "strconv" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -28,6 +30,7 @@ type OnchainClient interface { // For EVM specifically we can use existing geth interface // to abstract chain clients. bind.ContractBackend + bind.DeployBackend } type OffchainClient interface { @@ -62,6 +65,23 @@ func (e Environment) AllChainSelectors() []uint64 { return selectors } +func (e Environment) AllChainSelectorsExcluding(excluding []uint64) []uint64 { + var selectors []uint64 + for sel := range e.Chains { + excluded := false + for _, toExclude := range excluding { + if sel == toExclude { + excluded = true + } + } + if excluded { + continue + } + selectors = append(selectors, sel) + } + return selectors +} + func ConfirmIfNoError(chain Chain, tx *types.Transaction, err error) (uint64, error) { if err != nil { //revive:disable @@ -100,42 +120,68 @@ type OCRConfig struct { PeerID p2pkey.PeerID TransmitAccount types2.Account ConfigEncryptionPublicKey types3.ConfigEncryptionPublicKey - IsBootstrap bool - MultiAddr string // TODO: type + KeyBundleID string } +// Nodes includes is a group CL nodes. type Nodes []Node -func (n Nodes) PeerIDs(chainSel uint64) [][32]byte { +// PeerIDs returns peerIDs in a sorted list +func (n Nodes) PeerIDs() [][32]byte { var peerIDs [][32]byte for _, node := range n { - cfg := node.SelToOCRConfig[chainSel] - // NOTE: Assume same peerID for all chains. - // Might make sense to change proto as peerID is 1-1 with node? - peerIDs = append(peerIDs, cfg.PeerID) + peerIDs = append(peerIDs, node.PeerID) } + sort.Slice(peerIDs, func(i, j int) bool { + return bytes.Compare(peerIDs[i][:], peerIDs[j][:]) < 0 + }) return peerIDs } -func (n Nodes) BootstrapPeerIDs(chainSel uint64) [][32]byte { - var peerIDs [][32]byte +func (n Nodes) NonBootstraps() Nodes { + var nonBootstraps Nodes for _, node := range n { - cfg := node.SelToOCRConfig[chainSel] - if !cfg.IsBootstrap { + if node.IsBootstrap { continue } - peerIDs = append(peerIDs, cfg.PeerID) + nonBootstraps = append(nonBootstraps, node) } - return peerIDs + return nonBootstraps +} + +func (n Nodes) DefaultF() uint8 { + return uint8(len(n) / 3) +} + +func (n Nodes) BootstrapLocators() []string { + bootstrapMp := make(map[string]struct{}) + for _, node := range n { + if node.IsBootstrap { + bootstrapMp[fmt.Sprintf("%s@%s", + // p2p_12D3... -> 12D3... + node.PeerID.String()[4:], node.MultiAddr)] = struct{}{} + } + } + var locators []string + for b := range bootstrapMp { + locators = append(locators, b) + } + return locators } -// OffchainPublicKey types.OffchainPublicKey -// // For EVM-chains, this an *address*. -// OnchainPublicKey types.OnchainPublicKey -// PeerID string -// TransmitAccount types.Account type Node struct { + NodeID string SelToOCRConfig map[uint64]OCRConfig + PeerID p2pkey.PeerID + IsBootstrap bool + MultiAddr string +} + +func (n Node) FirstOCRKeybundle() OCRConfig { + for _, ocrConfig := range n.SelToOCRConfig { + return ocrConfig + } + return OCRConfig{} } func MustPeerIDFromString(s string) p2pkey.PeerID { @@ -150,20 +196,33 @@ func MustPeerIDFromString(s string) p2pkey.PeerID { // OCR config for example. func NodeInfo(nodeIDs []string, oc OffchainClient) (Nodes, error) { var nodes []Node - for _, node := range nodeIDs { + for _, nodeID := range nodeIDs { // TODO: Filter should accept multiple nodes nodeChainConfigs, err := oc.ListNodeChainConfigs(context.Background(), &nodev1.ListNodeChainConfigsRequest{Filter: &nodev1.ListNodeChainConfigsRequest_Filter{ - NodeIds: []string{node}, + NodeIds: []string{nodeID}, }}) if err != nil { return nil, err } selToOCRConfig := make(map[uint64]OCRConfig) + bootstrap := false + var peerID p2pkey.PeerID + var multiAddr string for _, chainConfig := range nodeChainConfigs.ChainConfigs { if chainConfig.Chain.Type == nodev1.ChainType_CHAIN_TYPE_SOLANA { // Note supported for CCIP yet. continue } + // NOTE: Assume same peerID/multiAddr for all chains. + // Might make sense to change proto as peerID/multiAddr is 1-1 with nodeID? + peerID = MustPeerIDFromString(chainConfig.Ocr2Config.P2PKeyBundle.PeerId) + multiAddr = chainConfig.Ocr2Config.Multiaddr + if chainConfig.Ocr2Config.IsBootstrap { + // NOTE: Assume same peerID for all chains. + // Might make sense to change proto as peerID is 1-1 with nodeID? + bootstrap = true + break + } evmChainID, err := strconv.Atoi(chainConfig.Chain.Id) if err != nil { return nil, err @@ -186,12 +245,15 @@ func NodeInfo(nodeIDs []string, oc OffchainClient) (Nodes, error) { PeerID: MustPeerIDFromString(chainConfig.Ocr2Config.P2PKeyBundle.PeerId), TransmitAccount: types2.Account(chainConfig.AccountAddress), ConfigEncryptionPublicKey: cpk, - IsBootstrap: chainConfig.Ocr2Config.IsBootstrap, - MultiAddr: chainConfig.Ocr2Config.Multiaddr, + KeyBundleID: chainConfig.Ocr2Config.OcrKeyBundle.BundleId, } } nodes = append(nodes, Node{ + NodeID: nodeID, SelToOCRConfig: selToOCRConfig, + IsBootstrap: bootstrap, + PeerID: peerID, + MultiAddr: multiAddr, }) } diff --git a/integration-tests/docs/VRF.md b/integration-tests/docs/VRF.md new file mode 100644 index 00000000000..745bec05864 --- /dev/null +++ b/integration-tests/docs/VRF.md @@ -0,0 +1,65 @@ +# How To Run VRF Tests +* All test configs should be placed in the [integration-tests/testconfig](../testconfig) folder +* All test configs for running tests in live testnets should be under [integration-tests/testconfig/vrfv2plus/overrides](../testconfig/vrfv2plus/overrides) folder + + +## Functional Tests +### In CI - using On Demand Workflows +```bash +gh workflow run "on-demand-vrfv2plus-smoke-tests.yml" \ +--ref develop \ +-f=test_secrets_override_key= \ +-f test_config_override_path= \ +-f test_suite="Selected Tests" \ # Optional, Options - "All Tests", "Selected Tests". Default is "All Tests". If "Selected Tests" is selected, then `test_list_regex` should be provided +-f test_list_regex="" \ # Optional, default is "TestVRFv2Plus$/(Link_Billing|Native_Billing|Direct_Funding)|TestVRFV2PlusWithBHS" which are P0 tests +-f chainlink_version="<>" # Optional, default is image created from develop branch. Not needed if you run tests against existing environment +-f notify_user_id_on_failure= # Optional, default is empty. If provided, will notify the user on slack if the tests fail +``` + +#### Examples: +Run P0 tests against existing environment (Staging) on Arbitrum Sepolia +```bash +gh workflow run "on-demand-vrfv2plus-smoke-tests.yml" \ +--ref develop \ +-f=test_secrets_override_key= \ +-f test_config_override_path=integration-tests/testconfig/vrfv2plus/overrides/staging/arbitrum_sepolia_staging_test_config.toml \ +-f test_suite="Selected Tests" +``` + +Run all tests deploying all contracts, CL nodes with `2.15.0` version on Base Sepolia +```bash +gh workflow run "on-demand-vrfv2plus-smoke-tests.yml" \ +--ref develop \ +-f=test_secrets_override_key= \ +-f test_config_override_path=integration-tests/testconfig/vrfv2plus/overrides/new_env/base_sepolia_new_env_test_config.toml \ +-f test_suite="All Tests" \ +-f chainlink_version="2.15.0" +``` + +### Locally +```bash +cd integration-tests +TEST_LOG_LEVEL=debug \ +BASE64_CONFIG_OVERRIDE=$(cat | base64) \ +go test -v -timeout 15m -run "" ./smoke +``` + +## Performance Tests +```bash +gh workflow run "on-demand-vrfv2plus-performance-test.yml" \ +--ref develop \ +-f=test_secrets_override_key= \ +-f test_config_override_path= \ +-f performanceTestType=“Smoke” # Options - "Smoke", "Soak", "Stress", "Load". +-f test_list_regex="" # Optional, default is "TestVRFV2PlusPerformance" +``` + +#### Examples: +Run SOAK tests against existing environment (Staging) on Base Sepolia +```bash +gh workflow run "on-demand-vrfv2plus-performance-test.yml" \ +--ref develop \ +-f=test_secrets_override_key= \ +-f test_config_override_path=integration-tests/testconfig/vrfv2plus/overrides/staging/base_sepolia_staging_test_config.toml \ +-f performanceTestType=“Soak” +``` diff --git a/integration-tests/go.mod b/integration-tests/go.mod index a260dbba6e6..75892f69477 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -33,11 +33,11 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/shopspring/decimal v1.4.0 github.com/slack-go/slack v0.12.2 - github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240808195812-ae0378684685 + github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240910151738-3f318badcfb5 github.com/smartcontractkit/chain-selectors v1.0.23 github.com/smartcontractkit/chainlink-automation v1.0.4 github.com/smartcontractkit/chainlink-ccip v0.0.0-20240911145028-d346e3ace978 - github.com/smartcontractkit/chainlink-common v0.2.2-0.20240911181800-d00d5184ffaa + github.com/smartcontractkit/chainlink-common v0.2.2-0.20240913161926-ce5d667907ce github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.0 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.5 github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 1ba9feb496f..f435992ae67 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1417,16 +1417,16 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ= github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= -github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240808195812-ae0378684685 h1:jakAsdhDxV4cMgRAcSvHraXjyePi8umG5SEUTGFvuy8= -github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240808195812-ae0378684685/go.mod h1:p7L/xNEQpHDdZtgFA6/FavuZHqvV3kYhQysxBywmq1k= +github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240910151738-3f318badcfb5 h1:m0HuGuVdRHqBBkHJpSR/QBV7gtLB+hFkXZQ9tEkjdzo= +github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240910151738-3f318badcfb5/go.mod h1:N60/wwocvZ5A3RGmYaMWo0fPFa5tTMlhI9lJ22DRktM= github.com/smartcontractkit/chain-selectors v1.0.23 h1:D2Eaex4Cw/O7Lg3tX6WklOqnjjIQAEBnutCtksPzVDY= github.com/smartcontractkit/chain-selectors v1.0.23/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8= github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= github.com/smartcontractkit/chainlink-ccip v0.0.0-20240911145028-d346e3ace978 h1:BPuehkAQ8R112SlTitukSdKYRJMY3zkvaQS4VSTNn0Q= github.com/smartcontractkit/chainlink-ccip v0.0.0-20240911145028-d346e3ace978/go.mod h1:X1f4CKlR1RilSgzArQv5HNvMrVSt+Zloihm3REwxhdQ= -github.com/smartcontractkit/chainlink-common v0.2.2-0.20240911181800-d00d5184ffaa h1:vG4aRggHzNDFTmMFemhhUAzqTfG159w0+RYjO7/cJ5E= -github.com/smartcontractkit/chainlink-common v0.2.2-0.20240911181800-d00d5184ffaa/go.mod h1:sjiiPwd4KsYOCf68MwL86EKphdXeT66EY7j53WH5DCc= +github.com/smartcontractkit/chainlink-common v0.2.2-0.20240913161926-ce5d667907ce h1:qXS0aWiDFDoLRCB+kSGnzp77iYT2luflUyzE5BnNmpY= +github.com/smartcontractkit/chainlink-common v0.2.2-0.20240913161926-ce5d667907ce/go.mod h1:sjiiPwd4KsYOCf68MwL86EKphdXeT66EY7j53WH5DCc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 h1:lTGIOQYLk1Ufn++X/AvZnt6VOcuhste5yp+C157No/Q= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7/go.mod h1:BMYE1vC/pGmdFSsOJdPrAA0/4gZ0Xo0SxTMdGspBtRo= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240906125718-9f0a98d32fbc h1:tRmTlaoAt+7FakMXXgeCuRPmzzBo5jsGpeCVvcU6KMc= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 86d9f5444b8..89a1f05a462 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -16,7 +16,7 @@ require ( github.com/rs/zerolog v1.33.0 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.4 - github.com/smartcontractkit/chainlink-common v0.2.2-0.20240911181800-d00d5184ffaa + github.com/smartcontractkit/chainlink-common v0.2.2-0.20240913161926-ce5d667907ce github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.5 github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.1 github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.0 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 9e50850d34e..a8a8d86d3a1 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1399,8 +1399,8 @@ github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8um github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= github.com/smartcontractkit/chainlink-ccip v0.0.0-20240911145028-d346e3ace978 h1:BPuehkAQ8R112SlTitukSdKYRJMY3zkvaQS4VSTNn0Q= github.com/smartcontractkit/chainlink-ccip v0.0.0-20240911145028-d346e3ace978/go.mod h1:X1f4CKlR1RilSgzArQv5HNvMrVSt+Zloihm3REwxhdQ= -github.com/smartcontractkit/chainlink-common v0.2.2-0.20240911181800-d00d5184ffaa h1:vG4aRggHzNDFTmMFemhhUAzqTfG159w0+RYjO7/cJ5E= -github.com/smartcontractkit/chainlink-common v0.2.2-0.20240911181800-d00d5184ffaa/go.mod h1:sjiiPwd4KsYOCf68MwL86EKphdXeT66EY7j53WH5DCc= +github.com/smartcontractkit/chainlink-common v0.2.2-0.20240913161926-ce5d667907ce h1:qXS0aWiDFDoLRCB+kSGnzp77iYT2luflUyzE5BnNmpY= +github.com/smartcontractkit/chainlink-common v0.2.2-0.20240913161926-ce5d667907ce/go.mod h1:sjiiPwd4KsYOCf68MwL86EKphdXeT66EY7j53WH5DCc= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 h1:lTGIOQYLk1Ufn++X/AvZnt6VOcuhste5yp+C157No/Q= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7/go.mod h1:BMYE1vC/pGmdFSsOJdPrAA0/4gZ0Xo0SxTMdGspBtRo= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240906125718-9f0a98d32fbc h1:tRmTlaoAt+7FakMXXgeCuRPmzzBo5jsGpeCVvcU6KMc= diff --git a/integration-tests/testconfig/vrfv2/overrides/new_env/arbitrum_sepolia_new_env_test_config.toml b/integration-tests/testconfig/vrfv2/overrides/new_env/arbitrum_sepolia_new_env_test_config.toml index e383bf27dae..9181c0f51fa 100644 --- a/integration-tests/testconfig/vrfv2/overrides/new_env/arbitrum_sepolia_new_env_test_config.toml +++ b/integration-tests/testconfig/vrfv2/overrides/new_env/arbitrum_sepolia_new_env_test_config.toml @@ -3,3 +3,6 @@ selected_networks = ["ARBITRUM_SEPOLIA"] [ARBITRUM_SEPOLIA.VRFv2.General] use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/integration-tests/testconfig/vrfv2/overrides/new_env/avalanche_fuji_new_env_test_config.toml b/integration-tests/testconfig/vrfv2/overrides/new_env/avalanche_fuji_new_env_test_config.toml index 7eb2215284c..cfeaa5a7975 100644 --- a/integration-tests/testconfig/vrfv2/overrides/new_env/avalanche_fuji_new_env_test_config.toml +++ b/integration-tests/testconfig/vrfv2/overrides/new_env/avalanche_fuji_new_env_test_config.toml @@ -3,3 +3,6 @@ selected_networks = ["AVALANCHE_FUJI"] [AVALANCHE_FUJI.VRFv2.General] use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/integration-tests/testconfig/vrfv2/overrides/new_env/bsc_testnet_new_env_test_config.toml b/integration-tests/testconfig/vrfv2/overrides/new_env/bsc_testnet_new_env_test_config.toml index 9652e94626f..ec938767ec5 100644 --- a/integration-tests/testconfig/vrfv2/overrides/new_env/bsc_testnet_new_env_test_config.toml +++ b/integration-tests/testconfig/vrfv2/overrides/new_env/bsc_testnet_new_env_test_config.toml @@ -3,3 +3,6 @@ selected_networks = ["BSC_TESTNET"] [BSC_TESTNET.VRFv2.General] use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/integration-tests/testconfig/vrfv2/overrides/new_env/polygon_amoy_new_env_test_config.toml b/integration-tests/testconfig/vrfv2/overrides/new_env/polygon_amoy_new_env_test_config.toml index 39d4ba849e6..6331647a883 100644 --- a/integration-tests/testconfig/vrfv2/overrides/new_env/polygon_amoy_new_env_test_config.toml +++ b/integration-tests/testconfig/vrfv2/overrides/new_env/polygon_amoy_new_env_test_config.toml @@ -3,3 +3,6 @@ selected_networks = ["POLYGON_AMOY"] [POLYGON_AMOY.VRFv2.General] use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/integration-tests/testconfig/vrfv2/overrides/new_env/sepolia_new_env_test_config.toml b/integration-tests/testconfig/vrfv2/overrides/new_env/sepolia_new_env_test_config.toml index 914dc266277..591f07e6625 100644 --- a/integration-tests/testconfig/vrfv2/overrides/new_env/sepolia_new_env_test_config.toml +++ b/integration-tests/testconfig/vrfv2/overrides/new_env/sepolia_new_env_test_config.toml @@ -3,3 +3,6 @@ selected_networks = ["SEPOLIA"] [SEPOLIA.VRFv2.General] use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/integration-tests/testconfig/vrfv2plus/overrides/new_env/arbitrum_sepolia_new_env_test_config.toml b/integration-tests/testconfig/vrfv2plus/overrides/new_env/arbitrum_sepolia_new_env_test_config.toml index 8f111a3ae09..271ef037bd3 100644 --- a/integration-tests/testconfig/vrfv2plus/overrides/new_env/arbitrum_sepolia_new_env_test_config.toml +++ b/integration-tests/testconfig/vrfv2plus/overrides/new_env/arbitrum_sepolia_new_env_test_config.toml @@ -3,3 +3,6 @@ selected_networks = ["ARBITRUM_SEPOLIA"] [ARBITRUM_SEPOLIA.VRFv2Plus.General] use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/integration-tests/testconfig/vrfv2plus/overrides/new_env/avalanche_fuji_new_env_test_config.toml b/integration-tests/testconfig/vrfv2plus/overrides/new_env/avalanche_fuji_new_env_test_config.toml index 8c7203ce7bb..273d796ba6f 100644 --- a/integration-tests/testconfig/vrfv2plus/overrides/new_env/avalanche_fuji_new_env_test_config.toml +++ b/integration-tests/testconfig/vrfv2plus/overrides/new_env/avalanche_fuji_new_env_test_config.toml @@ -3,3 +3,6 @@ selected_networks = ["AVALANCHE_FUJI"] [AVALANCHE_FUJI.VRFv2Plus.General] use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/integration-tests/testconfig/vrfv2plus/overrides/new_env/base_sepolia_new_env_test_config.toml b/integration-tests/testconfig/vrfv2plus/overrides/new_env/base_sepolia_new_env_test_config.toml index 9cbf7e58b95..f93c75cc380 100644 --- a/integration-tests/testconfig/vrfv2plus/overrides/new_env/base_sepolia_new_env_test_config.toml +++ b/integration-tests/testconfig/vrfv2plus/overrides/new_env/base_sepolia_new_env_test_config.toml @@ -3,3 +3,6 @@ selected_networks = ["BASE_SEPOLIA"] [BASE_SEPOLIA.VRFv2Plus.General] use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/integration-tests/testconfig/vrfv2plus/overrides/new_env/bsc_testnet_new_env_test_config.toml b/integration-tests/testconfig/vrfv2plus/overrides/new_env/bsc_testnet_new_env_test_config.toml index c3c07966fad..16cc9a6e539 100644 --- a/integration-tests/testconfig/vrfv2plus/overrides/new_env/bsc_testnet_new_env_test_config.toml +++ b/integration-tests/testconfig/vrfv2plus/overrides/new_env/bsc_testnet_new_env_test_config.toml @@ -3,3 +3,6 @@ selected_networks = ["BSC_TESTNET"] [BSC_TESTNET.VRFv2Plus.General] use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/integration-tests/testconfig/vrfv2plus/overrides/new_env/nexon_dev_new_env_test_config.toml b/integration-tests/testconfig/vrfv2plus/overrides/new_env/nexon_dev_new_env_test_config.toml index 5791b70660f..5d7b7741081 100644 --- a/integration-tests/testconfig/vrfv2plus/overrides/new_env/nexon_dev_new_env_test_config.toml +++ b/integration-tests/testconfig/vrfv2plus/overrides/new_env/nexon_dev_new_env_test_config.toml @@ -3,3 +3,6 @@ selected_networks = ["NEXON_DEV"] [NEXON_DEV.VRFv2Plus.General] use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/integration-tests/testconfig/vrfv2plus/overrides/new_env/nexon_qa_new_env_test_config.toml b/integration-tests/testconfig/vrfv2plus/overrides/new_env/nexon_qa_new_env_test_config.toml index fb16e8d0c4e..0f761128afa 100644 --- a/integration-tests/testconfig/vrfv2plus/overrides/new_env/nexon_qa_new_env_test_config.toml +++ b/integration-tests/testconfig/vrfv2plus/overrides/new_env/nexon_qa_new_env_test_config.toml @@ -3,3 +3,6 @@ selected_networks = ["NEXON_QA"] [NEXON_QA.VRFv2Plus.General] use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/integration-tests/testconfig/vrfv2plus/overrides/new_env/nexon_stage_new_env_test_config.toml b/integration-tests/testconfig/vrfv2plus/overrides/new_env/nexon_stage_new_env_test_config.toml index 9802b4de246..5dcd771e9dd 100644 --- a/integration-tests/testconfig/vrfv2plus/overrides/new_env/nexon_stage_new_env_test_config.toml +++ b/integration-tests/testconfig/vrfv2plus/overrides/new_env/nexon_stage_new_env_test_config.toml @@ -3,3 +3,6 @@ selected_networks = ["NEXON_STAGE"] [NEXON_STAGE.VRFv2Plus.General] use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/integration-tests/testconfig/vrfv2plus/overrides/new_env/nexon_test_new_env_test_config.toml b/integration-tests/testconfig/vrfv2plus/overrides/new_env/nexon_test_new_env_test_config.toml index ccaa4f332ad..d1263df34d0 100644 --- a/integration-tests/testconfig/vrfv2plus/overrides/new_env/nexon_test_new_env_test_config.toml +++ b/integration-tests/testconfig/vrfv2plus/overrides/new_env/nexon_test_new_env_test_config.toml @@ -3,3 +3,6 @@ selected_networks = ["NEXON_TEST"] [NEXON_TEST.VRFv2Plus.General] use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/integration-tests/testconfig/vrfv2plus/overrides/new_env/optimism_sepolia_new_env_test_config.toml b/integration-tests/testconfig/vrfv2plus/overrides/new_env/optimism_sepolia_new_env_test_config.toml index 1850365599e..8fd5b763796 100644 --- a/integration-tests/testconfig/vrfv2plus/overrides/new_env/optimism_sepolia_new_env_test_config.toml +++ b/integration-tests/testconfig/vrfv2plus/overrides/new_env/optimism_sepolia_new_env_test_config.toml @@ -3,3 +3,6 @@ selected_networks = ["OPTIMISM_SEPOLIA"] [OPTIMISM_SEPOLIA.VRFv2Plus.General] use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/integration-tests/testconfig/vrfv2plus/overrides/new_env/polygon_amoy_new_env_test_config.toml b/integration-tests/testconfig/vrfv2plus/overrides/new_env/polygon_amoy_new_env_test_config.toml index b5423bf6f75..10abe34bb5e 100644 --- a/integration-tests/testconfig/vrfv2plus/overrides/new_env/polygon_amoy_new_env_test_config.toml +++ b/integration-tests/testconfig/vrfv2plus/overrides/new_env/polygon_amoy_new_env_test_config.toml @@ -3,3 +3,6 @@ selected_networks = ["POLYGON_AMOY"] [POLYGON_AMOY.VRFv2Plus.General] use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/integration-tests/testconfig/vrfv2plus/overrides/new_env/sepolia_new_env_test_config.toml b/integration-tests/testconfig/vrfv2plus/overrides/new_env/sepolia_new_env_test_config.toml index 3be47f7d075..7df808c505f 100644 --- a/integration-tests/testconfig/vrfv2plus/overrides/new_env/sepolia_new_env_test_config.toml +++ b/integration-tests/testconfig/vrfv2plus/overrides/new_env/sepolia_new_env_test_config.toml @@ -3,3 +3,6 @@ selected_networks = ["SEPOLIA"] [SEPOLIA.VRFv2Plus.General] use_existing_env = false + +[Logging] +test_log_collect = true diff --git a/testdata/scripts/node/validate/default.txtar b/testdata/scripts/node/validate/default.txtar index 9dcec7a45c5..ad923919e08 100644 --- a/testdata/scripts/node/validate/default.txtar +++ b/testdata/scripts/node/validate/default.txtar @@ -47,7 +47,7 @@ LeaseDuration = '10s' LeaseRefreshInterval = '1s' [TelemetryIngress] -UniConn = true +UniConn = false Logging = false BufferSize = 100 MaxBatchSize = 50 diff --git a/testdata/scripts/node/validate/defaults-override.txtar b/testdata/scripts/node/validate/defaults-override.txtar index 3feb595be02..52eb86b3e6d 100644 --- a/testdata/scripts/node/validate/defaults-override.txtar +++ b/testdata/scripts/node/validate/defaults-override.txtar @@ -108,7 +108,7 @@ LeaseDuration = '10s' LeaseRefreshInterval = '1s' [TelemetryIngress] -UniConn = true +UniConn = false Logging = false BufferSize = 100 MaxBatchSize = 50 diff --git a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar index cd0e2f7fa1a..b9f456c4882 100644 --- a/testdata/scripts/node/validate/disk-based-logging-disabled.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-disabled.txtar @@ -91,7 +91,7 @@ LeaseDuration = '10s' LeaseRefreshInterval = '1s' [TelemetryIngress] -UniConn = true +UniConn = false Logging = false BufferSize = 100 MaxBatchSize = 50 diff --git a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar index 07ed2c398a3..9457ae718c7 100644 --- a/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar +++ b/testdata/scripts/node/validate/disk-based-logging-no-dir.txtar @@ -91,7 +91,7 @@ LeaseDuration = '10s' LeaseRefreshInterval = '1s' [TelemetryIngress] -UniConn = true +UniConn = false Logging = false BufferSize = 100 MaxBatchSize = 50 diff --git a/testdata/scripts/node/validate/disk-based-logging.txtar b/testdata/scripts/node/validate/disk-based-logging.txtar index 3bb1179218f..9a77ab1eac0 100644 --- a/testdata/scripts/node/validate/disk-based-logging.txtar +++ b/testdata/scripts/node/validate/disk-based-logging.txtar @@ -91,7 +91,7 @@ LeaseDuration = '10s' LeaseRefreshInterval = '1s' [TelemetryIngress] -UniConn = true +UniConn = false Logging = false BufferSize = 100 MaxBatchSize = 50 diff --git a/testdata/scripts/node/validate/invalid-ocr-p2p.txtar b/testdata/scripts/node/validate/invalid-ocr-p2p.txtar index 5c9d6765723..d3e56f97fbb 100644 --- a/testdata/scripts/node/validate/invalid-ocr-p2p.txtar +++ b/testdata/scripts/node/validate/invalid-ocr-p2p.txtar @@ -76,7 +76,7 @@ LeaseDuration = '10s' LeaseRefreshInterval = '1s' [TelemetryIngress] -UniConn = true +UniConn = false Logging = false BufferSize = 100 MaxBatchSize = 50 diff --git a/testdata/scripts/node/validate/invalid.txtar b/testdata/scripts/node/validate/invalid.txtar index e210c893823..af8fe17b877 100644 --- a/testdata/scripts/node/validate/invalid.txtar +++ b/testdata/scripts/node/validate/invalid.txtar @@ -81,7 +81,7 @@ LeaseDuration = '10s' LeaseRefreshInterval = '1s' [TelemetryIngress] -UniConn = true +UniConn = false Logging = false BufferSize = 100 MaxBatchSize = 50 diff --git a/testdata/scripts/node/validate/valid.txtar b/testdata/scripts/node/validate/valid.txtar index a11fd5f8926..c020664740c 100644 --- a/testdata/scripts/node/validate/valid.txtar +++ b/testdata/scripts/node/validate/valid.txtar @@ -88,7 +88,7 @@ LeaseDuration = '10s' LeaseRefreshInterval = '1s' [TelemetryIngress] -UniConn = true +UniConn = false Logging = false BufferSize = 100 MaxBatchSize = 50 diff --git a/testdata/scripts/node/validate/warnings.txtar b/testdata/scripts/node/validate/warnings.txtar index 071da2d2681..ac8489f3246 100644 --- a/testdata/scripts/node/validate/warnings.txtar +++ b/testdata/scripts/node/validate/warnings.txtar @@ -70,7 +70,7 @@ LeaseDuration = '10s' LeaseRefreshInterval = '1s' [TelemetryIngress] -UniConn = true +UniConn = false Logging = false BufferSize = 100 MaxBatchSize = 50 diff --git a/tools/bin/goreleaser_utils b/tools/bin/goreleaser_utils index fa9553274c5..979204d1e3a 100755 --- a/tools/bin/goreleaser_utils +++ b/tools/bin/goreleaser_utils @@ -25,7 +25,7 @@ _get_arch() { _get_wasmvm_lib_path() { local -r platform="$1" local -r arch="$2" - wasmvm_dir=$(go list -json -m all | jq -r '. | select(.Path == "github.com/CosmWasm/wasmvm") | .Dir') + wasmvm_dir=$(go list -json -m github.com/CosmWasm/wasmvm | jq -r '.Dir') shared_lib_dir="$wasmvm_dir/internal/api" lib_name="libwasmvm" if [ "$platform" == "darwin" ]; then