From 275cf371d240f4f1ff3b8ac459b011271ed0e4f3 Mon Sep 17 00:00:00 2001 From: pablolagreca Date: Tue, 12 Nov 2024 16:14:34 -0300 Subject: [PATCH 01/14] BCFR-967 - EVM Chain bindings for CR/CW - Basic support for method (#14657) * BCFR-967 - EVM Chain bindings for CR/CW - Basic support for method * updating chainlink-common dependency and updating test cases IDs * fixing test compilation issue * fixing lint and updating go.mod * updating go.mod for solana and common * updating go.mod for solana and common * removing go generation until is ready and plug into CI * ignoring flaky tests in CI * fixing lint issue --------- Co-authored-by: Pablo La Greca --- core/scripts/go.mod | 6 +- core/scripts/go.sum | 8 +- .../evm/bindings/chain_config_factory.go | 108 ++++ .../relay/evm/bindings/chain_reader_tester.go | 201 +++++++ .../relay/evm/chain_components_test.go | 4 +- .../chain_writer_historical_wrapper_test.go | 24 +- core/services/relay/evm/codec/codec_test.go | 4 +- .../evm/evmtesting/bindings_test_adapter.go | 523 +++++++++++++++++ .../chain_components_interface_tester.go | 134 +++-- .../relay/evm/evmtesting/run_tests.go | 533 ++++++++++-------- deployment/go.mod | 4 +- deployment/go.sum | 8 +- go.mod | 4 +- go.sum | 8 +- integration-tests/go.mod | 6 +- integration-tests/go.sum | 8 +- integration-tests/load/go.mod | 6 +- integration-tests/load/go.sum | 8 +- 18 files changed, 1264 insertions(+), 333 deletions(-) create mode 100644 core/services/relay/evm/bindings/chain_config_factory.go create mode 100644 core/services/relay/evm/bindings/chain_reader_tester.go create mode 100644 core/services/relay/evm/evmtesting/bindings_test_adapter.go diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 833bb2746cc..c713442cb06 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -24,9 +24,9 @@ require ( github.com/prometheus/client_golang v1.20.5 github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chainlink-automation v0.8.1 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241111184621-c61aebee0af9 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 github.com/smartcontractkit/chainlink/deployment v0.0.0-00010101000000-000000000000 - github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 + github.com/smartcontractkit/chainlink/v2 v2.14.0-mercury-20240807.0.20241106193309-5560cd76211a github.com/smartcontractkit/libocr v0.0.0-20241007185508-adbe57025f12 github.com/spf13/cobra v1.8.1 github.com/spf13/viper v1.19.0 @@ -300,7 +300,7 @@ require ( github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 // indirect - github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241104202120-39cabce465f6 // indirect + github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 // indirect github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 37c01952857..574647034ac 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1094,8 +1094,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 h1:BeLnOf2KKQpJj9nzfnE7QEg9ZqJ2jy/sbpNYVixVM2Y= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241111184621-c61aebee0af9 h1:xjrbuLW28nJ661Hu9dodcCQm7ElB5AWnZjmqGiGLNZg= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241111184621-c61aebee0af9/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 h1:yJNBWCdNL/X8+wEs3TGTBe9gssMmw5FTFxxrlo+0mVo= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f/go.mod h1:wHtwSR3F1CQSJJZDQKuqaqFYnvkT+kMyget7dl8Clvo= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e h1:JiETqdNM0bktAUGMc62COwXIaw3rR3M77Me6bBLG0Fg= @@ -1106,8 +1106,8 @@ github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 h1:1xTm8UGeD github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 h1:PBUaFfPLm+Efq7H9kdfGBivH+QhJ6vB5EZTR/sCZsxI= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241104202120-39cabce465f6 h1:YsE0uS6S10oAWnFbjNDc7tN9JrWYjvyqMnTSbTSgl00= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241104202120-39cabce465f6/go.mod h1:iZugccCLpPWtcGiR/8gurre2j3RtyKnqd1FcVR0NzQw= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 h1:blu++xbH/NSb+ii5hI4jczwojZ7Hc1ERXjpt/krYy9c= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930/go.mod h1:mGmRvlk54ufCufV4EBWizOGtXoXfePoFAuYEVC8EwdY= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 h1:B4DFdk6MGcQnoCjjMBCx7Z+GWQpxRWJ4O8W/dVJyWGA= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8/go.mod h1:WkBqgBo+g34Gm5vWkDDl8Fh3Mzd7bF5hXp7rryg0t5o= github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12ijqMM9tvYVEm+nR826WsrNi6zCKpwBhuApq127wHs= diff --git a/core/services/relay/evm/bindings/chain_config_factory.go b/core/services/relay/evm/bindings/chain_config_factory.go new file mode 100644 index 00000000000..4dfaffe80dc --- /dev/null +++ b/core/services/relay/evm/bindings/chain_config_factory.go @@ -0,0 +1,108 @@ +package bindings + +import ( + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +func NewChainReaderConfig() types.ChainReaderConfig { + chainReaderConfig := types.ChainReaderConfig{ + Contracts: map[string]types.ChainContractReader{ + "ChainReaderTester": types.ChainContractReader{ + Configs: map[string]*types.ChainReaderDefinition{ + "GetAlterablePrimitiveValue": &types.ChainReaderDefinition{ + CacheEnabled: false, + ChainSpecificName: "getAlterablePrimitiveValue", + ReadType: 0, + }, "GetDifferentPrimitiveValue": &types.ChainReaderDefinition{ + CacheEnabled: false, + ChainSpecificName: "getDifferentPrimitiveValue", + ReadType: 0, + }, "GetElementAtIndex": &types.ChainReaderDefinition{ + CacheEnabled: false, + ChainSpecificName: "getElementAtIndex", + ReadType: 0, + }, "GetPrimitiveValue": &types.ChainReaderDefinition{ + CacheEnabled: false, + ChainSpecificName: "getPrimitiveValue", + ReadType: 0, + }, "GetSliceValue": &types.ChainReaderDefinition{ + CacheEnabled: false, + ChainSpecificName: "getSliceValue", + ReadType: 0, + }, "ReturnSeen": &types.ChainReaderDefinition{ + CacheEnabled: false, + ChainSpecificName: "returnSeen", + ReadType: 0, + }, + }, + ContractABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"StaticBytes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"struct InnerDynamicTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"indexed\":false,\"internalType\":\"struct MidLevelDynamicTestStruct\",\"name\":\"nestedDynamicStruct\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"address\",\"name\":\"A\",\"type\":\"address\"}],\"internalType\":\"struct InnerStaticTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"indexed\":false,\"internalType\":\"struct MidLevelStaticTestStruct\",\"name\":\"nestedStaticStruct\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"AccountStr\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"struct AccountStruct\",\"name\":\"accountStruct\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"}],\"name\":\"Triggered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"string\",\"name\":\"fieldHash\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"field\",\"type\":\"string\"}],\"name\":\"TriggeredEventWithDynamicTopic\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field1\",\"type\":\"int32\"},{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field2\",\"type\":\"int32\"},{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field3\",\"type\":\"int32\"}],\"name\":\"TriggeredWithFourTopics\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"string\",\"name\":\"field1\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint8[32]\",\"name\":\"field2\",\"type\":\"uint8[32]\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"field3\",\"type\":\"bytes32\"}],\"name\":\"TriggeredWithFourTopicsWithHashed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"AccountStr\",\"type\":\"address\"}],\"internalType\":\"struct AccountStruct\",\"name\":\"accountStruct\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"struct InnerDynamicTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelDynamicTestStruct\",\"name\":\"nestedDynamicStruct\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"address\",\"name\":\"A\",\"type\":\"address\"}],\"internalType\":\"struct InnerStaticTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelStaticTestStruct\",\"name\":\"nestedStaticStruct\",\"type\":\"tuple\"}],\"name\":\"addTestStruct\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAlterablePrimitiveValue\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDifferentPrimitiveValue\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"i\",\"type\":\"uint256\"}],\"name\":\"getElementAtIndex\",\"outputs\":[{\"components\":[{\"internalType\":\"int32\",\"name\":\"Field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"DifferentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"OracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"OracleIds\",\"type\":\"uint8[32]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"AccountStr\",\"type\":\"address\"}],\"internalType\":\"struct AccountStruct\",\"name\":\"AccountStruct\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"BigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"struct InnerDynamicTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelDynamicTestStruct\",\"name\":\"NestedDynamicStruct\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"address\",\"name\":\"A\",\"type\":\"address\"}],\"internalType\":\"struct InnerStaticTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelStaticTestStruct\",\"name\":\"NestedStaticStruct\",\"type\":\"tuple\"}],\"internalType\":\"struct TestStruct\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPrimitiveValue\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSliceValue\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"AccountStr\",\"type\":\"address\"}],\"internalType\":\"struct AccountStruct\",\"name\":\"accountStruct\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"struct InnerDynamicTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelDynamicTestStruct\",\"name\":\"nestedDynamicStruct\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"address\",\"name\":\"A\",\"type\":\"address\"}],\"internalType\":\"struct InnerStaticTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelStaticTestStruct\",\"name\":\"nestedStaticStruct\",\"type\":\"tuple\"}],\"name\":\"returnSeen\",\"outputs\":[{\"components\":[{\"internalType\":\"int32\",\"name\":\"Field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"DifferentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"OracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"OracleIds\",\"type\":\"uint8[32]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"AccountStr\",\"type\":\"address\"}],\"internalType\":\"struct AccountStruct\",\"name\":\"AccountStruct\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"BigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"struct InnerDynamicTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelDynamicTestStruct\",\"name\":\"NestedDynamicStruct\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"address\",\"name\":\"A\",\"type\":\"address\"}],\"internalType\":\"struct InnerStaticTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelStaticTestStruct\",\"name\":\"NestedStaticStruct\",\"type\":\"tuple\"}],\"internalType\":\"struct TestStruct\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"value\",\"type\":\"uint64\"}],\"name\":\"setAlterablePrimitiveValue\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"struct InnerDynamicTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelDynamicTestStruct\",\"name\":\"nestedDynamicStruct\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"address\",\"name\":\"A\",\"type\":\"address\"}],\"internalType\":\"struct InnerStaticTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelStaticTestStruct\",\"name\":\"nestedStaticStruct\",\"type\":\"tuple\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"AccountStr\",\"type\":\"address\"}],\"internalType\":\"struct AccountStruct\",\"name\":\"accountStruct\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"}],\"name\":\"triggerEvent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"field\",\"type\":\"string\"}],\"name\":\"triggerEventWithDynamicTopic\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"val1\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"val2\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"val3\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"val4\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"val5\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"val6\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"val7\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"raw\",\"type\":\"bytes\"}],\"name\":\"triggerStaticBytes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field1\",\"type\":\"int32\"},{\"internalType\":\"int32\",\"name\":\"field2\",\"type\":\"int32\"},{\"internalType\":\"int32\",\"name\":\"field3\",\"type\":\"int32\"}],\"name\":\"triggerWithFourTopics\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"field1\",\"type\":\"string\"},{\"internalType\":\"uint8[32]\",\"name\":\"field2\",\"type\":\"uint8[32]\"},{\"internalType\":\"bytes32\",\"name\":\"field3\",\"type\":\"bytes32\"}],\"name\":\"triggerWithFourTopicsWithHashed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ContractPollingFilter: types.ContractPollingFilter{ + PollingFilter: types.PollingFilter{ + LogsPerBlock: 0, + MaxLogsKept: 0, + Retention: 0, + }, + }, + }, + }, + } + return chainReaderConfig +} + +func NewChainWriterConfig(maxGasPrice assets.Wei, defaultGasPrice uint64, fromAddress common.Address) types.ChainWriterConfig { + chainWriterConfig := types.ChainWriterConfig{ + Contracts: map[string]*types.ContractConfig{ + "ChainReaderTester": &types.ContractConfig{ + Configs: map[string]*types.ChainWriterDefinition{ + "AddTestStruct": &types.ChainWriterDefinition{ + ChainSpecificName: "addTestStruct", + Checker: "simulate", + FromAddress: fromAddress, + GasLimit: 0, + }, "SetAlterablePrimitiveValue": &types.ChainWriterDefinition{ + ChainSpecificName: "setAlterablePrimitiveValue", + Checker: "simulate", + FromAddress: fromAddress, + GasLimit: 0, + }, "TriggerEvent": &types.ChainWriterDefinition{ + ChainSpecificName: "triggerEvent", + Checker: "simulate", + FromAddress: fromAddress, + GasLimit: 0, + }, "TriggerEventWithDynamicTopic": &types.ChainWriterDefinition{ + ChainSpecificName: "triggerEventWithDynamicTopic", + Checker: "simulate", + FromAddress: fromAddress, + GasLimit: 0, + }, "TriggerStaticBytes": &types.ChainWriterDefinition{ + ChainSpecificName: "triggerStaticBytes", + Checker: "simulate", + FromAddress: fromAddress, + GasLimit: 0, + }, "TriggerWithFourTopics": &types.ChainWriterDefinition{ + ChainSpecificName: "triggerWithFourTopics", + Checker: "simulate", + FromAddress: fromAddress, + GasLimit: 0, + }, "TriggerWithFourTopicsWithHashed": &types.ChainWriterDefinition{ + ChainSpecificName: "triggerWithFourTopicsWithHashed", + Checker: "simulate", + FromAddress: fromAddress, + GasLimit: 0, + }, + }, + ContractABI: "[{\"inputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"StaticBytes\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"struct InnerDynamicTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"indexed\":false,\"internalType\":\"struct MidLevelDynamicTestStruct\",\"name\":\"nestedDynamicStruct\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"address\",\"name\":\"A\",\"type\":\"address\"}],\"internalType\":\"struct InnerStaticTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"indexed\":false,\"internalType\":\"struct MidLevelStaticTestStruct\",\"name\":\"nestedStaticStruct\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"AccountStr\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"struct AccountStruct\",\"name\":\"accountStruct\",\"type\":\"tuple\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"}],\"name\":\"Triggered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"string\",\"name\":\"fieldHash\",\"type\":\"string\"},{\"indexed\":false,\"internalType\":\"string\",\"name\":\"field\",\"type\":\"string\"}],\"name\":\"TriggeredEventWithDynamicTopic\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field1\",\"type\":\"int32\"},{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field2\",\"type\":\"int32\"},{\"indexed\":true,\"internalType\":\"int32\",\"name\":\"field3\",\"type\":\"int32\"}],\"name\":\"TriggeredWithFourTopics\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"string\",\"name\":\"field1\",\"type\":\"string\"},{\"indexed\":true,\"internalType\":\"uint8[32]\",\"name\":\"field2\",\"type\":\"uint8[32]\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"field3\",\"type\":\"bytes32\"}],\"name\":\"TriggeredWithFourTopicsWithHashed\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"AccountStr\",\"type\":\"address\"}],\"internalType\":\"struct AccountStruct\",\"name\":\"accountStruct\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"struct InnerDynamicTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelDynamicTestStruct\",\"name\":\"nestedDynamicStruct\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"address\",\"name\":\"A\",\"type\":\"address\"}],\"internalType\":\"struct InnerStaticTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelStaticTestStruct\",\"name\":\"nestedStaticStruct\",\"type\":\"tuple\"}],\"name\":\"addTestStruct\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAlterablePrimitiveValue\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDifferentPrimitiveValue\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"i\",\"type\":\"uint256\"}],\"name\":\"getElementAtIndex\",\"outputs\":[{\"components\":[{\"internalType\":\"int32\",\"name\":\"Field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"DifferentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"OracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"OracleIds\",\"type\":\"uint8[32]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"AccountStr\",\"type\":\"address\"}],\"internalType\":\"struct AccountStruct\",\"name\":\"AccountStruct\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"BigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"struct InnerDynamicTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelDynamicTestStruct\",\"name\":\"NestedDynamicStruct\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"address\",\"name\":\"A\",\"type\":\"address\"}],\"internalType\":\"struct InnerStaticTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelStaticTestStruct\",\"name\":\"NestedStaticStruct\",\"type\":\"tuple\"}],\"internalType\":\"struct TestStruct\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getPrimitiveValue\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getSliceValue\",\"outputs\":[{\"internalType\":\"uint64[]\",\"name\":\"\",\"type\":\"uint64[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"AccountStr\",\"type\":\"address\"}],\"internalType\":\"struct AccountStruct\",\"name\":\"accountStruct\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"struct InnerDynamicTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelDynamicTestStruct\",\"name\":\"nestedDynamicStruct\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"address\",\"name\":\"A\",\"type\":\"address\"}],\"internalType\":\"struct InnerStaticTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelStaticTestStruct\",\"name\":\"nestedStaticStruct\",\"type\":\"tuple\"}],\"name\":\"returnSeen\",\"outputs\":[{\"components\":[{\"internalType\":\"int32\",\"name\":\"Field\",\"type\":\"int32\"},{\"internalType\":\"string\",\"name\":\"DifferentField\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"OracleId\",\"type\":\"uint8\"},{\"internalType\":\"uint8[32]\",\"name\":\"OracleIds\",\"type\":\"uint8[32]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"AccountStr\",\"type\":\"address\"}],\"internalType\":\"struct AccountStruct\",\"name\":\"AccountStruct\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"Accounts\",\"type\":\"address[]\"},{\"internalType\":\"int192\",\"name\":\"BigField\",\"type\":\"int192\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"struct InnerDynamicTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelDynamicTestStruct\",\"name\":\"NestedDynamicStruct\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"address\",\"name\":\"A\",\"type\":\"address\"}],\"internalType\":\"struct InnerStaticTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelStaticTestStruct\",\"name\":\"NestedStaticStruct\",\"type\":\"tuple\"}],\"internalType\":\"struct TestStruct\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"value\",\"type\":\"uint64\"}],\"name\":\"setAlterablePrimitiveValue\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field\",\"type\":\"int32\"},{\"internalType\":\"uint8\",\"name\":\"oracleId\",\"type\":\"uint8\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"string\",\"name\":\"S\",\"type\":\"string\"}],\"internalType\":\"struct InnerDynamicTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelDynamicTestStruct\",\"name\":\"nestedDynamicStruct\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"bytes2\",\"name\":\"FixedBytes\",\"type\":\"bytes2\"},{\"components\":[{\"internalType\":\"int64\",\"name\":\"IntVal\",\"type\":\"int64\"},{\"internalType\":\"address\",\"name\":\"A\",\"type\":\"address\"}],\"internalType\":\"struct InnerStaticTestStruct\",\"name\":\"Inner\",\"type\":\"tuple\"}],\"internalType\":\"struct MidLevelStaticTestStruct\",\"name\":\"nestedStaticStruct\",\"type\":\"tuple\"},{\"internalType\":\"uint8[32]\",\"name\":\"oracleIds\",\"type\":\"uint8[32]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"Account\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"AccountStr\",\"type\":\"address\"}],\"internalType\":\"struct AccountStruct\",\"name\":\"accountStruct\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"accounts\",\"type\":\"address[]\"},{\"internalType\":\"string\",\"name\":\"differentField\",\"type\":\"string\"},{\"internalType\":\"int192\",\"name\":\"bigField\",\"type\":\"int192\"}],\"name\":\"triggerEvent\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"field\",\"type\":\"string\"}],\"name\":\"triggerEventWithDynamicTopic\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"val1\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"val2\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"val3\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"val4\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"val5\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"val6\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"val7\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"raw\",\"type\":\"bytes\"}],\"name\":\"triggerStaticBytes\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"int32\",\"name\":\"field1\",\"type\":\"int32\"},{\"internalType\":\"int32\",\"name\":\"field2\",\"type\":\"int32\"},{\"internalType\":\"int32\",\"name\":\"field3\",\"type\":\"int32\"}],\"name\":\"triggerWithFourTopics\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"field1\",\"type\":\"string\"},{\"internalType\":\"uint8[32]\",\"name\":\"field2\",\"type\":\"uint8[32]\"},{\"internalType\":\"bytes32\",\"name\":\"field3\",\"type\":\"bytes32\"}],\"name\":\"triggerWithFourTopicsWithHashed\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + }, + }, + } + chainWriterConfig.MaxGasPrice = &maxGasPrice + for _, contract := range chainWriterConfig.Contracts { + for _, chainWriterDefinition := range contract.Configs { + chainWriterDefinition.GasLimit = defaultGasPrice + } + } + return chainWriterConfig +} diff --git a/core/services/relay/evm/bindings/chain_reader_tester.go b/core/services/relay/evm/bindings/chain_reader_tester.go new file mode 100644 index 00000000000..f15f1431679 --- /dev/null +++ b/core/services/relay/evm/bindings/chain_reader_tester.go @@ -0,0 +1,201 @@ +// Code generated evm-bindings; DO NOT EDIT. + +package bindings + +import ( + "context" + "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" + "math/big" +) + +// CodeDetails methods inputs and outputs structs +type ChainReaderTester struct { + BoundContract types.BoundContract + ContractReader types.ContractReader + ChainWriter types.ChainWriter +} + +type AccountStruct struct { + Account []byte + AccountStr []byte +} + +type AddTestStructInput struct { + Field int32 + DifferentField string + OracleId uint8 + OracleIds [32]uint8 + AccountStruct AccountStruct + Accounts [][]byte + BigField *big.Int + NestedDynamicStruct MidLevelDynamicTestStruct + NestedStaticStruct MidLevelStaticTestStruct +} + +type GetAlterablePrimitiveValueOutput struct { + Value uint64 +} + +type GetDifferentPrimitiveValueOutput struct { + Value uint64 +} + +type GetElementAtIndexInput struct { + I *big.Int +} + +type GetPrimitiveValueOutput struct { + Value uint64 +} + +type GetSliceValueOutput struct { + Value []uint64 +} + +type InnerDynamicTestStruct struct { + IntVal int64 + S string +} + +type InnerStaticTestStruct struct { + IntVal int64 + A []byte +} + +type MidLevelDynamicTestStruct struct { + FixedBytes [2]uint8 + Inner InnerDynamicTestStruct +} + +type MidLevelStaticTestStruct struct { + FixedBytes [2]uint8 + Inner InnerStaticTestStruct +} + +type ReturnSeenInput struct { + Field int32 + DifferentField string + OracleId uint8 + OracleIds [32]uint8 + AccountStruct AccountStruct + Accounts [][]byte + BigField *big.Int + NestedDynamicStruct MidLevelDynamicTestStruct + NestedStaticStruct MidLevelStaticTestStruct +} + +type SetAlterablePrimitiveValueInput struct { + Value uint64 +} + +type TestStruct struct { + Field int32 + DifferentField string + OracleId uint8 + OracleIds [32]uint8 + AccountStruct AccountStruct + Accounts [][]byte + BigField *big.Int + NestedDynamicStruct MidLevelDynamicTestStruct + NestedStaticStruct MidLevelStaticTestStruct +} + +type TriggerEventInput struct { + Field int32 + OracleId uint8 + NestedDynamicStruct MidLevelDynamicTestStruct + NestedStaticStruct MidLevelStaticTestStruct + OracleIds [32]uint8 + AccountStruct AccountStruct + Accounts [][]byte + DifferentField string + BigField *big.Int +} + +type TriggerEventWithDynamicTopicInput struct { + Field string +} + +type TriggerStaticBytesInput struct { + Val1 uint32 + Val2 uint32 + Val3 uint32 + Val4 uint64 + Val5 [32]uint8 + Val6 [32]uint8 + Val7 [32]uint8 + Raw []uint8 +} + +type TriggerWithFourTopicsInput struct { + Field1 int32 + Field2 int32 + Field3 int32 +} + +type TriggerWithFourTopicsWithHashedInput struct { + Field1 string + Field2 [32]uint8 + Field3 [32]uint8 +} + +func (b ChainReaderTester) GetPrimitiveValue(ctx context.Context, confidence primitives.ConfidenceLevel) (uint64, error) { + var output uint64 + err := b.ContractReader.GetLatestValue(ctx, b.BoundContract.ReadIdentifier("GetPrimitiveValue"), confidence, nil, &output) + return output, err +} + +func (b ChainReaderTester) GetSliceValue(ctx context.Context, confidence primitives.ConfidenceLevel) ([]uint64, error) { + var output []uint64 + err := b.ContractReader.GetLatestValue(ctx, b.BoundContract.ReadIdentifier("GetSliceValue"), confidence, nil, &output) + return output, err +} + +func (b ChainReaderTester) ReturnSeen(ctx context.Context, input ReturnSeenInput, confidence primitives.ConfidenceLevel) (TestStruct, error) { + output := TestStruct{} + err := b.ContractReader.GetLatestValue(ctx, b.BoundContract.ReadIdentifier("ReturnSeen"), confidence, input, &output) + return output, err +} + +func (b ChainReaderTester) TriggerEvent(ctx context.Context, input TriggerEventInput, txId string, toAddress string, meta *types.TxMeta) error { + return b.ChainWriter.SubmitTransaction(ctx, "ChainReaderTester", "TriggerEvent", input, txId, toAddress, meta, big.NewInt(0)) +} + +func (b ChainReaderTester) GetDifferentPrimitiveValue(ctx context.Context, confidence primitives.ConfidenceLevel) (uint64, error) { + var output uint64 + err := b.ContractReader.GetLatestValue(ctx, b.BoundContract.ReadIdentifier("GetDifferentPrimitiveValue"), confidence, nil, &output) + return output, err +} + +func (b ChainReaderTester) GetElementAtIndex(ctx context.Context, input GetElementAtIndexInput, confidence primitives.ConfidenceLevel) (TestStruct, error) { + output := TestStruct{} + err := b.ContractReader.GetLatestValue(ctx, b.BoundContract.ReadIdentifier("GetElementAtIndex"), confidence, input, &output) + return output, err +} + +func (b ChainReaderTester) SetAlterablePrimitiveValue(ctx context.Context, input SetAlterablePrimitiveValueInput, txId string, toAddress string, meta *types.TxMeta) error { + return b.ChainWriter.SubmitTransaction(ctx, "ChainReaderTester", "SetAlterablePrimitiveValue", input, txId, toAddress, meta, big.NewInt(0)) +} + +func (b ChainReaderTester) TriggerEventWithDynamicTopic(ctx context.Context, input TriggerEventWithDynamicTopicInput, txId string, toAddress string, meta *types.TxMeta) error { + return b.ChainWriter.SubmitTransaction(ctx, "ChainReaderTester", "TriggerEventWithDynamicTopic", input, txId, toAddress, meta, big.NewInt(0)) +} + +func (b ChainReaderTester) TriggerWithFourTopics(ctx context.Context, input TriggerWithFourTopicsInput, txId string, toAddress string, meta *types.TxMeta) error { + return b.ChainWriter.SubmitTransaction(ctx, "ChainReaderTester", "TriggerWithFourTopics", input, txId, toAddress, meta, big.NewInt(0)) +} + +func (b ChainReaderTester) TriggerWithFourTopicsWithHashed(ctx context.Context, input TriggerWithFourTopicsWithHashedInput, txId string, toAddress string, meta *types.TxMeta) error { + return b.ChainWriter.SubmitTransaction(ctx, "ChainReaderTester", "TriggerWithFourTopicsWithHashed", input, txId, toAddress, meta, big.NewInt(0)) +} + +func (b ChainReaderTester) AddTestStruct(ctx context.Context, input AddTestStructInput, txId string, toAddress string, meta *types.TxMeta) error { + return b.ChainWriter.SubmitTransaction(ctx, "ChainReaderTester", "AddTestStruct", input, txId, toAddress, meta, big.NewInt(0)) +} + +func (b ChainReaderTester) GetAlterablePrimitiveValue(ctx context.Context, confidence primitives.ConfidenceLevel) (uint64, error) { + var output uint64 + err := b.ContractReader.GetLatestValue(ctx, b.BoundContract.ReadIdentifier("GetAlterablePrimitiveValue"), confidence, nil, &output) + return output, err +} diff --git a/core/services/relay/evm/chain_components_test.go b/core/services/relay/evm/chain_components_test.go index b46b644e681..91e41295e48 100644 --- a/core/services/relay/evm/chain_components_test.go +++ b/core/services/relay/evm/chain_components_test.go @@ -207,12 +207,12 @@ func TestContractReaderEventsInitValidation(t *testing.T) { func TestChainComponents(t *testing.T) { t.Parallel() it := &EVMChainComponentsInterfaceTester[*testing.T]{Helper: &helper{}} - - it.Helper.Init(t) + it.Init(t) // add new subtests here so that it can be run on real chains too RunChainComponentsEvmTests(t, it) RunChainComponentsInLoopEvmTests[*testing.T](t, commontestutils.WrapContractReaderTesterForLoop(it)) + RunChainComponentsInLoopEvmTests(t, WrapContractReaderTesterWithBindings(t, it)) } type helper struct { diff --git a/core/services/relay/evm/chain_writer_historical_wrapper_test.go b/core/services/relay/evm/chain_writer_historical_wrapper_test.go index c849d1f3d57..233d7bc2e2f 100644 --- a/core/services/relay/evm/chain_writer_historical_wrapper_test.go +++ b/core/services/relay/evm/chain_writer_historical_wrapper_test.go @@ -2,11 +2,13 @@ package evm import ( "context" + "math/big" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" interfacetesttypes "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" - primitives "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" + "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/bindings" ) // This wrapper is required to enable the ChainReader to access historical data @@ -22,7 +24,8 @@ func NewChainWriterHistoricalWrapper(cw commontypes.ChainWriter, cwh *ClientWith } func (cwhw *ChainWriterHistoricalWrapper) SubmitTransaction(ctx context.Context, contractName, method string, args any, transactionID string, toAddress string, meta *commontypes.TxMeta, value *big.Int) error { - if primArgs, ok := args.(interfacetesttypes.PrimitiveArgs); ok { + alterablePrimitiveCall, newValue := cwhw.getPrimitiveValueIfPossible(args) + if alterablePrimitiveCall { callArgs := interfacetesttypes.ExpectedGetLatestValueArgs{ ContractName: contractName, ReadName: "GetAlterablePrimitiveValue", @@ -30,10 +33,25 @@ func (cwhw *ChainWriterHistoricalWrapper) SubmitTransaction(ctx context.Context, Params: nil, ReturnVal: nil, } - err := cwhw.cwh.SetUintLatestValue(ctx, primArgs.Value, callArgs) + err := cwhw.cwh.SetUintLatestValue(ctx, newValue, callArgs) if err != nil { return err } } return cwhw.ChainWriter.SubmitTransaction(ctx, contractName, method, args, transactionID, toAddress, meta, value) } + +func (cwhw *ChainWriterHistoricalWrapper) getPrimitiveValueIfPossible(args any) (bool, uint64) { + primitiveArgs, alterablePrimitiveCall := args.(interfacetesttypes.PrimitiveArgs) + var newValue uint64 + var alterablePrimitiveValue bindings.SetAlterablePrimitiveValueInput + if alterablePrimitiveCall { + newValue = primitiveArgs.Value + } else { + alterablePrimitiveValue, alterablePrimitiveCall = args.(bindings.SetAlterablePrimitiveValueInput) + if alterablePrimitiveCall { + newValue = alterablePrimitiveValue.Value + } + } + return alterablePrimitiveCall, newValue +} diff --git a/core/services/relay/evm/codec/codec_test.go b/core/services/relay/evm/codec/codec_test.go index d63ed5342c4..2da88abaac1 100644 --- a/core/services/relay/evm/codec/codec_test.go +++ b/core/services/relay/evm/codec/codec_test.go @@ -172,7 +172,9 @@ func TestCodec_EncodeTupleWithLists(t *testing.T) { require.Equal(t, expected, hexutil.Encode(result)[2:]) } -type codecInterfaceTester struct{} +type codecInterfaceTester struct { + TestSelectionSupport +} func (it *codecInterfaceTester) Setup(_ *testing.T) {} diff --git a/core/services/relay/evm/evmtesting/bindings_test_adapter.go b/core/services/relay/evm/evmtesting/bindings_test_adapter.go new file mode 100644 index 00000000000..3dd625266ad --- /dev/null +++ b/core/services/relay/evm/evmtesting/bindings_test_adapter.go @@ -0,0 +1,523 @@ +package evmtesting + +import ( + "context" + "errors" + "fmt" + "math/big" + "reflect" + "strings" + "testing" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/go-viper/mapstructure/v2" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" + "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/bindings" + evmcodec "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/codec" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" +) + +const contractName = "ChainReaderTester" + +// Wraps EVMChainComponentsInterfaceTester to rely on the EVM bindings generated for CR/CW instead of going directly to CR/CW. This way we can reuse all existing tests. Transformation between expected +// contract names and read keys will be done here as well as invocation delegation to generated code. +func WrapContractReaderTesterWithBindings(t *testing.T, wrapped *EVMChainComponentsInterfaceTester[*testing.T]) interfacetests.ChainComponentsInterfaceTester[*testing.T] { + // Tests not yet supported by EVM bindings. + wrapped.DisableTests([]string{ + interfacetests.ContractReaderGetLatestValueAsValuesDotValue, interfacetests.ContractReaderGetLatestValueNoArgumentsAndPrimitiveReturnAsValuesDotValue, interfacetests.ContractReaderGetLatestValueNoArgumentsAndSliceReturnAsValueDotValue, + interfacetests.ContractReaderGetLatestValueGetsLatestForEvent, interfacetests.ContractReaderGetLatestValueBasedOnConfidenceLevelForEvent, + interfacetests.ContractReaderGetLatestValueReturnsNotFoundWhenNotTriggeredForEvent, interfacetests.ContractReaderGetLatestValueWithFilteringForEvent, interfacetests.ContractReaderBatchGetLatestValue, interfacetests.ContractReaderBatchGetLatestValueMultipleContractNamesSameFunction, + interfacetests.ContractReaderBatchGetLatestValueDifferentParamsResultsRetainOrder, interfacetests.ContractReaderBatchGetLatestValueDifferentParamsResultsRetainOrderMultipleContracts, interfacetests.ContractReaderBatchGetLatestValueNoArgumentsPrimitiveReturn, + interfacetests.ContractReaderBatchGetLatestValueSetsErrorsProperly, interfacetests.ContractReaderBatchGetLatestValueNoArgumentsWithSliceReturn, interfacetests.ContractReaderBatchGetLatestValueWithModifiersOwnMapstructureOverride, + interfacetests.ContractReaderQueryKeyNotFound, interfacetests.ContractReaderQueryKeyReturnsData, interfacetests.ContractReaderQueryKeyReturnsDataAsValuesDotValue, interfacetests.ContractReaderQueryKeyReturnsDataAsValuesDotValue, + interfacetests.ContractReaderQueryKeyCanFilterWithValueComparator, interfacetests.ContractReaderQueryKeyCanLimitResultsWithCursor, + ContractReaderQueryKeyFilterOnDataWordsWithValueComparator, ContractReaderQueryKeyOnDataWordsWithValueComparatorOnNestedField, + ContractReaderQueryKeyFilterOnDataWordsWithValueComparatorOnDynamicField, ContractReaderQueryKeyFilteringOnDataWordsUsingValueComparatorsOnFieldsWithManualIndex, + // TODO BCFR-1073 - Fix flaky tests + interfacetests.ContractReaderGetLatestValueBasedOnConfidenceLevel, + }) + wrapped.SetChainReaderConfigSupplier(func(t *testing.T) types.ChainReaderConfig { + return getChainReaderConfig(wrapped) + }) + wrapped.SetChainWriterConfigSupplier(func(t *testing.T) types.ChainWriterConfig { + return getChainWriterConfig(t, wrapped) + }) + return newBindingClientTester(wrapped) +} + +func newBindingClientTester(wrapped *EVMChainComponentsInterfaceTester[*testing.T]) bindingClientTester { + bindingsMapping := newBindingsMapping() + return bindingClientTester{ + ChainComponentsInterfaceTester: wrapped, + bindingsMapping: &bindingsMapping, + } +} + +func newBindingsMapping() bindingsMapping { + contractReaderProxy := bindingContractReaderProxy{} + chainWriterProxy := bindingChainWriterProxy{} + methodNameMappingByContract := make(map[string]map[string]string) + methodNameMappingByContract[interfacetests.AnyContractName] = map[string]string{ + interfacetests.MethodTakingLatestParamsReturningTestStruct: "GetElementAtIndex", + interfacetests.MethodReturningSeenStruct: "ReturnSeen", + interfacetests.MethodReturningAlterableUint64: "GetAlterablePrimitiveValue", + interfacetests.MethodReturningUint64: "GetPrimitiveValue", + interfacetests.MethodReturningUint64Slice: "getSliceValue", + interfacetests.MethodSettingStruct: "AddTestStruct", + interfacetests.MethodSettingUint64: "SetAlterablePrimitiveValue", + interfacetests.MethodTriggeringEvent: "TriggerEvent", + } + methodNameMappingByContract[interfacetests.AnySecondContractName] = map[string]string{ + interfacetests.MethodReturningUint64: "GetDifferentPrimitiveValue", + } + + bm := bindingsMapping{ + contractNameMapping: map[string]string{ + interfacetests.AnyContractName: contractName, + interfacetests.AnySecondContractName: contractName, + }, + methodNameMappingByContract: methodNameMappingByContract, + contractReaderProxy: &contractReaderProxy, + chainWriterProxy: &chainWriterProxy, + chainReaderTesters: map[string]*bindings.ChainReaderTester{}, + } + contractReaderProxy.bm = &bm + chainWriterProxy.bm = &bm + bm.createDelegates() + return bm +} + +func getChainReaderConfig(wrapped *EVMChainComponentsInterfaceTester[*testing.T]) types.ChainReaderConfig { + testStruct := interfacetests.CreateTestStruct[*testing.T](0, wrapped) + chainReaderConfig := bindings.NewChainReaderConfig() + chainReaderConfig.Contracts["ChainReaderTester"].Configs["ReturnSeen"] = &types.ChainReaderDefinition{ + CacheEnabled: false, + ChainSpecificName: "returnSeen", + ReadType: 0, + InputModifications: codec.ModifiersConfig{ + &codec.HardCodeModifierConfig{ + OnChainValues: map[string]any{ + "BigField": testStruct.BigField.String(), + "AccountStruct.Account": hexutil.Encode(testStruct.AccountStruct.Account), + }, + }, + }, + OutputModifications: codec.ModifiersConfig{ + &codec.HardCodeModifierConfig{OffChainValues: map[string]any{"ExtraField": interfacetests.AnyExtraValue}}, + }, + } + return chainReaderConfig +} + +func getChainWriterConfig(t *testing.T, wrapped *EVMChainComponentsInterfaceTester[*testing.T]) types.ChainWriterConfig { + return bindings.NewChainWriterConfig(*assets.NewWei(big.NewInt(1000000000000000000)), 2_000_000, wrapped.Helper.Accounts(t)[1].From) +} + +func (b bindingClientTester) Name() string { + return "generated bindings" +} + +type bindingClientTester struct { + interfacetests.ChainComponentsInterfaceTester[*testing.T] + bindingsMapping *bindingsMapping +} + +func (b bindingClientTester) GetContractReader(t *testing.T) commontypes.ContractReader { + contractReader := b.ChainComponentsInterfaceTester.GetContractReader(t) + if b.bindingsMapping.contractReaderProxy.ContractReader == nil { + b.bindingsMapping.contractReaderProxy.ContractReader = contractReader + b.addDefaultBindings(t) + for _, tester := range b.bindingsMapping.chainReaderTesters { + tester.ContractReader = contractReader + } + } + return b.bindingsMapping.contractReaderProxy +} + +func (b bindingClientTester) addDefaultBindings(t *testing.T) { + defaultBindings := b.ChainComponentsInterfaceTester.GetBindings(t) + for _, binding := range defaultBindings { + chainReaderTester := b.bindingsMapping.chainReaderTesters[binding.Address] + if chainReaderTester == nil { + chainReaderTester = &bindings.ChainReaderTester{ + BoundContract: binding, + ChainWriter: b.bindingsMapping.chainWriterProxy.ChainWriter, + } + b.bindingsMapping.chainReaderTesters[binding.Address] = chainReaderTester + } else { + chainReaderTester.ChainWriter = b.bindingsMapping.chainWriterProxy.ChainWriter + } + } +} + +func (b bindingClientTester) GetChainWriter(t *testing.T) commontypes.ChainWriter { + chainWriter := b.ChainComponentsInterfaceTester.GetChainWriter(t) + if b.bindingsMapping.chainWriterProxy.ChainWriter == nil { + b.addDefaultBindings(t) + for _, tester := range b.bindingsMapping.chainReaderTesters { + tester.ChainWriter = chainWriter + } + b.bindingsMapping.chainWriterProxy.ChainWriter = chainWriter + } + return b.bindingsMapping.chainWriterProxy +} + +type bindingsMapping struct { + contractNameMapping map[string]string + methodNameMappingByContract map[string]map[string]string + delegates map[string]*Delegate + chainReaderTesters map[string]*bindings.ChainReaderTester + contractReaderProxy *bindingContractReaderProxy + chainWriterProxy *bindingChainWriterProxy +} + +type bindingContractReaderProxy struct { + commontypes.ContractReader + bm *bindingsMapping +} + +type bindingChainWriterProxy struct { + commontypes.ChainWriter + bm *bindingsMapping +} + +func (b bindingContractReaderProxy) Bind(ctx context.Context, boundContracts []commontypes.BoundContract) error { + updatedBindings := b.bm.translateContractNames(boundContracts) + for _, updatedBinding := range updatedBindings { + b.bm.chainReaderTesters[updatedBinding.Address] = &bindings.ChainReaderTester{ + BoundContract: updatedBinding, + ContractReader: b.ContractReader, + ChainWriter: b.bm.chainWriterProxy.ChainWriter, + } + } + return b.ContractReader.Bind(ctx, updatedBindings) +} + +func (b bindingsMapping) translateContractNames(boundContracts []commontypes.BoundContract) []commontypes.BoundContract { + updatedBindings := make([]commontypes.BoundContract, 0, len(boundContracts)) + for _, boundContract := range boundContracts { + updatedBindings = append(updatedBindings, commontypes.BoundContract{ + Address: boundContract.Address, + Name: b.translateContractName(boundContract.Name), + }) + } + return updatedBindings +} + +func (b bindingContractReaderProxy) Close() error { + return b.ContractReader.Close() +} + +func (b bindingContractReaderProxy) GetLatestValue(ctx context.Context, readKey string, confidenceLevel primitives.ConfidenceLevel, params, returnVal any) error { + delegate, err := b.bm.getBindingDelegate(readKey) + if err != nil { + return err + } + output, err := delegate.apply(ctx, readKey, params, confidenceLevel) + if err != nil { + return err + } + if output == nil { + return nil + } + err = convertStruct(output, returnVal) + if err != nil { + return err + } + return nil +} + +func (b bindingChainWriterProxy) SubmitTransaction(ctx context.Context, contract, method string, args any, transactionID string, toAddress string, meta *commontypes.TxMeta, value *big.Int) error { + chainReaderTesters := b.bm.chainReaderTesters[toAddress] + switch contract { + case interfacetests.AnyContractName, interfacetests.AnySecondContractName: + switch method { + case interfacetests.MethodSettingStruct: + bindingsInput := bindings.AddTestStructInput{} + _ = convertStruct(args, &bindingsInput) + return chainReaderTesters.AddTestStruct(ctx, bindingsInput, transactionID, toAddress, meta) + case interfacetests.MethodSettingUint64: + bindingsInput := bindings.SetAlterablePrimitiveValueInput{} + _ = convertStruct(args, &bindingsInput) + return chainReaderTesters.SetAlterablePrimitiveValue(ctx, bindingsInput, transactionID, toAddress, meta) + case interfacetests.MethodTriggeringEvent: + bindingsInput := bindings.TriggerEventInput{} + _ = convertStruct(args, &bindingsInput) + return chainReaderTesters.TriggerEvent(ctx, bindingsInput, transactionID, toAddress, meta) + default: + return errors.New("No logic implemented for method: " + method) + } + default: + return errors.New("contract with id not supported " + contract) + } +} + +func (b *bindingChainWriterProxy) GetTransactionStatus(ctx context.Context, transactionID string) (commontypes.TransactionStatus, error) { + return b.ChainWriter.GetTransactionStatus(ctx, transactionID) +} + +func removeAddressFromReadIdentifier(s string) string { + index := strings.Index(s, "-") + if index == -1 { + return s + } + return s[index+1:] +} + +func (b *bindingsMapping) createDelegates() { + delegates := make(map[string]*Delegate) + boundContract := commontypes.BoundContract{Address: "", Name: contractName} + methodTakingLatestParamsKey := removeAddressFromReadIdentifier(boundContract.ReadIdentifier(b.methodNameMappingByContract[interfacetests.AnyContractName][interfacetests.MethodTakingLatestParamsReturningTestStruct])) + delegates[methodTakingLatestParamsKey] = b.createDelegateForMethodTakingLatestParams() + methodReturningAlterableUint64Key := removeAddressFromReadIdentifier(boundContract.ReadIdentifier(b.methodNameMappingByContract[interfacetests.AnyContractName][interfacetests.MethodReturningAlterableUint64])) + delegates[methodReturningAlterableUint64Key] = b.createDelegateForMethodReturningAlterableUint64() + methodReturningSeenStructKey := removeAddressFromReadIdentifier(boundContract.ReadIdentifier(b.methodNameMappingByContract[interfacetests.AnyContractName][interfacetests.MethodReturningSeenStruct])) + delegates[methodReturningSeenStructKey] = b.createDelegateForMethodReturningSeenStruct() + methodReturningUint64Key := removeAddressFromReadIdentifier(boundContract.ReadIdentifier(b.methodNameMappingByContract[interfacetests.AnyContractName][interfacetests.MethodReturningUint64])) + delegates[methodReturningUint64Key] = b.createDelegateForMethodReturningUint64() + methodReturningUint64SliceKey := removeAddressFromReadIdentifier(boundContract.ReadIdentifier(b.methodNameMappingByContract[interfacetests.AnyContractName][interfacetests.MethodReturningUint64Slice])) + delegates[methodReturningUint64SliceKey] = b.createDelegateForMethodReturningUint64Slice() + methodReturningDifferentUint64Key := removeAddressFromReadIdentifier(boundContract.ReadIdentifier(b.methodNameMappingByContract[interfacetests.AnySecondContractName][interfacetests.MethodReturningUint64])) + delegates[methodReturningDifferentUint64Key] = b.createDelegateForSecondContractMethodReturningUint64() + b.delegates = delegates +} + +func (b *bindingsMapping) createDelegateForMethodTakingLatestParams() *Delegate { + delegate := Delegate{inputType: reflect.TypeOf(bindings.GetElementAtIndexInput{})} + delegate.delegateFunc = func(ctx context.Context, readyKey string, input *any, level primitives.ConfidenceLevel) (any, error) { + methodInvocation := func(ctx context.Context, readKey string, input *bindings.GetElementAtIndexInput, level primitives.ConfidenceLevel) (any, error) { + chainReaderTester := b.GetChainReaderTester(readKey) + return chainReaderTester.GetElementAtIndex(ctx, *input, level) + } + return invokeSpecificMethod(ctx, b.translateReadKey(readyKey), (*input).(*bindings.GetElementAtIndexInput), level, methodInvocation) + } + return &delegate +} + +func (b *bindingsMapping) createDelegateForMethodReturningAlterableUint64() *Delegate { + delegate := Delegate{} + delegate.delegateFunc = func(ctx context.Context, readyKey string, input *any, level primitives.ConfidenceLevel) (any, error) { + methodInvocation := func(ctx context.Context, readKey string, input any, level primitives.ConfidenceLevel) (any, error) { + chainReaderTester := b.GetChainReaderTester(readKey) + return chainReaderTester.GetAlterablePrimitiveValue(ctx, level) + } + return invokeSpecificMethod(ctx, b.translateReadKey(readyKey), nil, level, methodInvocation) + } + return &delegate +} + +func (b *bindingsMapping) createDelegateForMethodReturningSeenStruct() *Delegate { + delegate := Delegate{inputType: reflect.TypeOf(bindings.ReturnSeenInput{})} + delegate.delegateFunc = func(ctx context.Context, readyKey string, input *any, level primitives.ConfidenceLevel) (any, error) { + methodInvocation := func(ctx context.Context, readKey string, input *bindings.ReturnSeenInput, level primitives.ConfidenceLevel) (any, error) { + chainReaderTester := b.GetChainReaderTester(readKey) + return chainReaderTester.ReturnSeen(ctx, *input, level) + } + return invokeSpecificMethod(ctx, b.translateReadKey(readyKey), (*input).(*bindings.ReturnSeenInput), level, methodInvocation) + } + return &delegate +} + +func (b *bindingsMapping) createDelegateForMethodReturningUint64() *Delegate { + delegate := Delegate{} + delegate.delegateFunc = func(ctx context.Context, readyKey string, input *any, level primitives.ConfidenceLevel) (any, error) { + methodInvocation := func(ctx context.Context, readKey string, input any, level primitives.ConfidenceLevel) (any, error) { + chainReaderTester := b.GetChainReaderTester(readKey) + return chainReaderTester.GetPrimitiveValue(ctx, level) + } + return invokeSpecificMethod(ctx, b.translateReadKey(readyKey), nil, level, methodInvocation) + } + return &delegate +} + +func (b *bindingsMapping) createDelegateForMethodReturningUint64Slice() *Delegate { + delegate := Delegate{} + delegate.delegateFunc = func(ctx context.Context, readyKey string, input *any, level primitives.ConfidenceLevel) (any, error) { + methodInvocation := func(ctx context.Context, readKey string, input any, level primitives.ConfidenceLevel) (any, error) { + chainReaderTester := b.GetChainReaderTester(readKey) + return chainReaderTester.GetSliceValue(ctx, level) + } + return invokeSpecificMethod(ctx, b.translateReadKey(readyKey), nil, level, methodInvocation) + } + return &delegate +} + +func (b *bindingsMapping) createDelegateForSecondContractMethodReturningUint64() *Delegate { + delegate := Delegate{} + delegate.delegateFunc = func(ctx context.Context, readyKey string, input *any, level primitives.ConfidenceLevel) (any, error) { + methodInvocation := func(ctx context.Context, readKey string, input any, level primitives.ConfidenceLevel) (any, error) { + chainReaderTester := b.GetChainReaderTester(readKey) + return chainReaderTester.GetDifferentPrimitiveValue(ctx, level) + } + return invokeSpecificMethod(ctx, b.translateReadKey(readyKey), nil, level, methodInvocation) + } + return &delegate +} + +// Transforms a readKey from ChainReader using the generic testing config to the actual config being used with go bindings which is the auto-generated from the solidity contract. +func (b bindingsMapping) translateReadKey(key string) string { + var updatedKey = key + parts := strings.Split(key, "-") + contractName := parts[1] + methodName := parts[2] + for testConfigName, bindingsName := range b.contractNameMapping { + if contractName == testConfigName { + updatedKey = strings.Replace(updatedKey, testConfigName, bindingsName, 1) + } + } + for testConfigName, bindingsName := range b.methodNameMappingByContract[contractName] { + if methodName == testConfigName { + updatedKey = strings.Replace(updatedKey, testConfigName, bindingsName, 1) + } + } + return updatedKey +} + +// Transforms a readKey from ChainReader using the generic testing config to the actual config being used with go bindings which is the auto-generated from the solidity contract. +func (b bindingsMapping) translateContractName(contractName string) string { + for testContractName, bindingsName := range b.contractNameMapping { + if contractName == testContractName { + return bindingsName + } + } + return contractName +} + +func invokeSpecificMethod[T any](ctx context.Context, readKey string, input T, level primitives.ConfidenceLevel, methodInvocation func(ctx context.Context, readKey string, input T, level primitives.ConfidenceLevel) (any, error)) (any, error) { + return methodInvocation(ctx, readKey, input, level) +} + +func (b bindingsMapping) getBindingDelegate(readKey string) (*Delegate, error) { + translatedKey := removeAddressFromReadIdentifier(b.translateReadKey(readKey)) + delegate := b.delegates[translatedKey] + + if delegate == nil { + return nil, fmt.Errorf("delegate not found for readerKey %s", translatedKey) + } + return delegate, nil +} + +func (b bindingsMapping) GetChainReaderTester(key string) *bindings.ChainReaderTester { + address := key[0:strings.Index(key, "-")] + return b.chainReaderTesters[address] +} + +type Delegate struct { + inputType reflect.Type + delegateFunc func(context.Context, string, *any, primitives.ConfidenceLevel) (any, error) +} + +func (d Delegate) getInput(input any) (*any, error) { + if input == nil { + return nil, nil + } + adaptedInput := reflect.New(d.inputType).Interface() + err := convertStruct(input, adaptedInput) + if err != nil { + return nil, err + } + return &adaptedInput, nil +} + +func (d Delegate) apply(ctx context.Context, readKey string, input any, confidenceLevel primitives.ConfidenceLevel) (any, error) { + adaptedInput, err := d.getInput(input) + if err != nil { + return nil, err + } + output, err := d.delegateFunc(ctx, readKey, adaptedInput, confidenceLevel) + if err != nil { + return nil, err + } + return output, nil +} + +// Utility function to converted original types from and to bindings expected types. +func convertStruct(src any, dst any) error { + if reflect.TypeOf(src).Kind() == reflect.Ptr && reflect.TypeOf(dst).Kind() == reflect.Ptr && reflect.TypeOf(src).Elem() == reflect.TypeOf(interfacetests.LatestParams{}) && reflect.TypeOf(dst).Elem() == reflect.TypeOf(bindings.GetElementAtIndexInput{}) { + value := src.(*interfacetests.LatestParams).I + dst.(*bindings.GetElementAtIndexInput).I = big.NewInt(int64(value)) + return nil + } + decoder, err := createDecoder(dst) + if err != nil { + return err + } + err = decoder.Decode(src) + if err != nil { + return err + } + switch { + case reflect.TypeOf(dst).Elem() == reflect.TypeOf(interfacetests.TestStructWithExtraField{}): + destTestStruct := dst.(*interfacetests.TestStructWithExtraField) + if destTestStruct != nil { + auxTestStruct := &interfacetests.TestStruct{} + decoder, _ := createDecoder(auxTestStruct) + _ = decoder.Decode(src) + destTestStruct.TestStruct = *auxTestStruct + sourceTestStruct := src.(bindings.TestStruct) + destTestStruct.BigField = sourceTestStruct.BigField + destTestStruct.NestedStaticStruct.Inner.I = int(sourceTestStruct.NestedStaticStruct.Inner.IntVal) + destTestStruct.NestedStaticStruct.FixedBytes = sourceTestStruct.NestedStaticStruct.FixedBytes + destTestStruct.NestedDynamicStruct.Inner.I = int(sourceTestStruct.NestedDynamicStruct.Inner.IntVal) + destTestStruct.NestedDynamicStruct.FixedBytes = sourceTestStruct.NestedDynamicStruct.FixedBytes + destTestStruct.ExtraField = interfacetests.AnyExtraValue + } + case reflect.TypeOf(dst).Elem() == reflect.TypeOf(interfacetests.TestStruct{}): + destTestStruct := dst.(*interfacetests.TestStruct) + if destTestStruct != nil { + sourceTestStruct := src.(bindings.TestStruct) + destTestStruct.BigField = sourceTestStruct.BigField + destTestStruct.NestedStaticStruct.Inner.I = int(sourceTestStruct.NestedStaticStruct.Inner.IntVal) + destTestStruct.NestedStaticStruct.FixedBytes = sourceTestStruct.NestedStaticStruct.FixedBytes + destTestStruct.NestedDynamicStruct.Inner.I = int(sourceTestStruct.NestedDynamicStruct.Inner.IntVal) + destTestStruct.NestedDynamicStruct.FixedBytes = sourceTestStruct.NestedDynamicStruct.FixedBytes + } + case reflect.TypeOf(src) == reflect.TypeOf(interfacetests.TestStruct{}) && reflect.TypeOf(dst) == reflect.TypeOf(&bindings.AddTestStructInput{}): + destTestStruct := dst.(*bindings.AddTestStructInput) + if destTestStruct != nil { + sourceTestStruct := src.(interfacetests.TestStruct) + destTestStruct.BigField = sourceTestStruct.BigField + destTestStruct.NestedStaticStruct.Inner.IntVal = int64(sourceTestStruct.NestedStaticStruct.Inner.I) + destTestStruct.NestedStaticStruct.FixedBytes = sourceTestStruct.NestedStaticStruct.FixedBytes + destTestStruct.NestedDynamicStruct.Inner.IntVal = int64(sourceTestStruct.NestedDynamicStruct.Inner.I) + destTestStruct.NestedDynamicStruct.FixedBytes = sourceTestStruct.NestedDynamicStruct.FixedBytes + } + case reflect.TypeOf(src) == reflect.TypeOf(interfacetests.TestStruct{}) && reflect.TypeOf(dst) == reflect.TypeOf(&bindings.ReturnSeenInput{}): + destTestStruct := dst.(*bindings.ReturnSeenInput) + if destTestStruct != nil { + sourceTestStruct := src.(interfacetests.TestStruct) + destTestStruct.BigField = sourceTestStruct.BigField + destTestStruct.NestedStaticStruct.Inner.IntVal = int64(sourceTestStruct.NestedStaticStruct.Inner.I) + destTestStruct.NestedStaticStruct.FixedBytes = sourceTestStruct.NestedStaticStruct.FixedBytes + destTestStruct.NestedDynamicStruct.Inner.IntVal = int64(sourceTestStruct.NestedDynamicStruct.Inner.I) + destTestStruct.NestedDynamicStruct.FixedBytes = sourceTestStruct.NestedDynamicStruct.FixedBytes + } + } + return err +} + +func createDecoder(dst any) (*mapstructure.Decoder, error) { + decoderConfig := &mapstructure.DecoderConfig{ + DecodeHook: mapstructure.ComposeDecodeHookFunc( + stringToByteArrayHook, + ), + Result: dst, + } + decoder, err := mapstructure.NewDecoder(decoderConfig) + return decoder, err +} + +func stringToByteArrayHook(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) { + if from.Kind() == reflect.String && to == reflect.TypeOf([]byte{}) { + return evmcodec.EVMAddressModifier{}.DecodeAddress(data.(string)) + } + if from == reflect.TypeOf([]byte{}) && to.Kind() == reflect.String { + return evmcodec.EVMAddressModifier{}.EncodeAddress(data.([]byte)) + } + return data, nil +} diff --git a/core/services/relay/evm/evmtesting/chain_components_interface_tester.go b/core/services/relay/evm/evmtesting/chain_components_interface_tester.go index c0d1754f6fd..9655fb78457 100644 --- a/core/services/relay/evm/evmtesting/chain_components_interface_tester.go +++ b/core/services/relay/evm/evmtesting/chain_components_interface_tester.go @@ -14,7 +14,7 @@ import ( "github.com/smartcontractkit/libocr/commontypes" "github.com/stretchr/testify/require" - commoncodec "github.com/smartcontractkit/chainlink-common/pkg/codec" + "github.com/smartcontractkit/chainlink-common/pkg/codec" clcommontypes "github.com/smartcontractkit/chainlink-common/pkg/types" . "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with . "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" @@ -60,20 +60,24 @@ type EVMChainComponentsInterfaceTesterHelper[T TestingT[T]] interface { } type EVMChainComponentsInterfaceTester[T TestingT[T]] struct { - Helper EVMChainComponentsInterfaceTesterHelper[T] - client client.Client - address string - address2 string - contractTesters map[string]*chain_reader_tester.ChainReaderTester - chainReaderConfig types.ChainReaderConfig - chainWriterConfig types.ChainWriterConfig - deployerAuth *bind.TransactOpts - senderAuth *bind.TransactOpts - cr evm.ChainReaderService - cw evm.ChainWriterService - dirtyContracts bool - txm evmtxmgr.TxManager - gasEstimator gas.EvmFeeEstimator + TestSelectionSupport + Helper EVMChainComponentsInterfaceTesterHelper[T] + client client.Client + address string + address2 string + contractTesters map[string]*chain_reader_tester.ChainReaderTester + chainReaderConfig types.ChainReaderConfig + chainWriterConfig types.ChainWriterConfig + deployerAuth *bind.TransactOpts + senderAuth *bind.TransactOpts + cr evm.ChainReaderService + cw evm.ChainWriterService + dirtyContracts bool + txm evmtxmgr.TxManager + gasEstimator gas.EvmFeeEstimator + chainReaderConfigSupplier func(t T) types.ChainReaderConfig + chainWriterConfigSupplier func(t T) types.ChainWriterConfig + dirtyConfig bool } func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) { @@ -95,7 +99,7 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) { }) // can re-use the same chain for tests, just make new contract for each test - if it.client != nil { + if it.client != nil && !it.dirtyConfig { it.deployNewContracts(t) return } @@ -106,20 +110,31 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) { it.deployerAuth = accounts[0] it.senderAuth = accounts[1] + it.chainReaderConfig = it.chainReaderConfigSupplier(t) + it.GetContractReader(t) + + it.txm = it.Helper.TXM(t, it.client) + it.chainWriterConfig = it.chainWriterConfigSupplier(t) + + it.deployNewContracts(t) + it.dirtyConfig = false +} + +func (it *EVMChainComponentsInterfaceTester[T]) getChainReaderConfig(t T) types.ChainReaderConfig { testStruct := CreateTestStruct[T](0, it) methodTakingLatestParamsReturningTestStructConfig := types.ChainReaderDefinition{ ChainSpecificName: "getElementAtIndex", - OutputModifications: commoncodec.ModifiersConfig{ - &commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}}, - &commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}}, - &commoncodec.AddressBytesToStringModifierConfig{ + OutputModifications: codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}}, + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}}, + &codec.AddressBytesToStringModifierConfig{ Fields: []string{"AccountStruct.AccountStr"}, }, }, } - it.chainReaderConfig = types.ChainReaderConfig{ + return types.ChainReaderConfig{ Contracts: map[string]types.ChainContractReader{ AnyContractName: { ContractABI: chain_reader_tester.ChainReaderTesterMetaData.ABI, @@ -150,10 +165,10 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) { "BigField": {Name: "bigField"}, }, }, - OutputModifications: commoncodec.ModifiersConfig{ - &commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}}, - &commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}}, - &commoncodec.AddressBytesToStringModifierConfig{ + OutputModifications: codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}}, + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}}, + &codec.AddressBytesToStringModifierConfig{ Fields: []string{"AccountStruct.AccountStr"}, }, }, @@ -174,8 +189,8 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) { EventWithFilterName: { ChainSpecificName: "Triggered", ReadType: types.Event, - OutputModifications: commoncodec.ModifiersConfig{ - &commoncodec.AddressBytesToStringModifierConfig{ + OutputModifications: codec.ModifiersConfig{ + &codec.AddressBytesToStringModifierConfig{ Fields: []string{"AccountStruct.AccountStr"}, }, }, @@ -187,8 +202,8 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) { // No specific reason for filter being defined here instead of on contract level, this is just for test case variety. PollingFilter: &types.PollingFilter{}, }, - InputModifications: commoncodec.ModifiersConfig{ - &commoncodec.RenameModifierConfig{Fields: map[string]string{"FieldHash": "Field"}}, + InputModifications: codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"FieldHash": "Field"}}, }, }, triggerWithAllTopics: { @@ -209,24 +224,24 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) { }, MethodReturningSeenStruct: { ChainSpecificName: "returnSeen", - InputModifications: commoncodec.ModifiersConfig{ - &commoncodec.HardCodeModifierConfig{ + InputModifications: codec.ModifiersConfig{ + &codec.HardCodeModifierConfig{ OnChainValues: map[string]any{ "BigField": testStruct.BigField.String(), "AccountStruct.Account": hexutil.Encode(testStruct.AccountStruct.Account), }, }, - &commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}}, - &commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}}, - &commoncodec.AddressBytesToStringModifierConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}}, + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}}, + &codec.AddressBytesToStringModifierConfig{ Fields: []string{"AccountStruct.AccountStr"}, }, }, - OutputModifications: commoncodec.ModifiersConfig{ - &commoncodec.HardCodeModifierConfig{OffChainValues: map[string]any{"ExtraField": AnyExtraValue}}, - &commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}}, - &commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}}, - &commoncodec.AddressBytesToStringModifierConfig{ + OutputModifications: codec.ModifiersConfig{ + &codec.HardCodeModifierConfig{OffChainValues: map[string]any{"ExtraField": AnyExtraValue}}, + &codec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}}, + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}}, + &codec.AddressBytesToStringModifierConfig{ Fields: []string{"AccountStruct.AccountStr"}, }, }, @@ -244,10 +259,10 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) { }, }, } - it.GetContractReader(t) - it.txm = it.Helper.TXM(t, it.client) +} - it.chainWriterConfig = types.ChainWriterConfig{ +func (it *EVMChainComponentsInterfaceTester[T]) getChainWriterConfig(t T) types.ChainWriterConfig { + return types.ChainWriterConfig{ Contracts: map[string]*types.ContractConfig{ AnyContractName: { ContractABI: chain_reader_tester.ChainReaderTesterMetaData.ABI, @@ -257,9 +272,9 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) { FromAddress: it.Helper.Accounts(t)[1].From, GasLimit: 2_000_000, Checker: "simulate", - InputModifications: commoncodec.ModifiersConfig{ - &commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}}, - &commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}}, + InputModifications: codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}}, + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}}, }, }, "setAlterablePrimitiveValue": { @@ -273,9 +288,9 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) { FromAddress: it.Helper.Accounts(t)[1].From, GasLimit: 2_000_000, Checker: "simulate", - InputModifications: commoncodec.ModifiersConfig{ - &commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}}, - &commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}}, + InputModifications: codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}}, + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}}, }, }, "triggerEventWithDynamicTopic": { @@ -312,9 +327,9 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) { FromAddress: it.Helper.Accounts(t)[1].From, GasLimit: 2_000_000, Checker: "simulate", - InputModifications: commoncodec.ModifiersConfig{ - &commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}}, - &commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}}, + InputModifications: codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}}, + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}}, }, }, }, @@ -322,7 +337,6 @@ func (it *EVMChainComponentsInterfaceTester[T]) Setup(t T) { }, MaxGasPrice: assets.NewWei(big.NewInt(1000000000000000000)), } - it.deployNewContracts(t) } func (it *EVMChainComponentsInterfaceTester[T]) Name() string { @@ -461,6 +475,22 @@ func (it *EVMChainComponentsInterfaceTester[T]) MaxWaitTimeForEvents() time.Dura return it.Helper.MaxWaitTimeForEvents() } +func (it *EVMChainComponentsInterfaceTester[T]) Init(t T) { + it.Helper.Init(t) + it.chainWriterConfigSupplier = func(t T) types.ChainWriterConfig { return it.getChainWriterConfig(t) } + it.chainReaderConfigSupplier = func(t T) types.ChainReaderConfig { return it.getChainReaderConfig(t) } +} + +func (it *EVMChainComponentsInterfaceTester[T]) SetChainReaderConfigSupplier(chainReaderConfigSupplier func(t T) types.ChainReaderConfig) { + it.dirtyConfig = true + it.chainReaderConfigSupplier = chainReaderConfigSupplier +} + +func (it *EVMChainComponentsInterfaceTester[T]) SetChainWriterConfigSupplier(chainWriterConfigSupplier func(t T) types.ChainWriterConfig) { + it.dirtyConfig = true + it.chainWriterConfigSupplier = chainWriterConfigSupplier +} + func OracleIDsToBytes(oracleIDs [32]commontypes.OracleID) [32]byte { convertedIDs := [32]byte{} for i, id := range oracleIDs { diff --git a/core/services/relay/evm/evmtesting/run_tests.go b/core/services/relay/evm/evmtesting/run_tests.go index 2efe1c3f08a..5f3cdbb2fd7 100644 --- a/core/services/relay/evm/evmtesting/run_tests.go +++ b/core/services/relay/evm/evmtesting/run_tests.go @@ -21,6 +21,17 @@ import ( . "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with . ) +const ( + ContractReaderQueryKeyFilterOnDataWordsWithValueComparator = "Filtering can be done on data words using value comparator" + ContractReaderQueryKeyOnDataWordsWithValueComparatorOnNestedField = "Filtering can be done on data words using value comparator on a nested field" + ContractReaderQueryKeyFilterOnDataWordsWithValueComparatorOnDynamicField = "Filtering can be done on data words using value comparator on field that follows a dynamic field" + ContractReaderQueryKeyFilteringOnDataWordsUsingValueComparatorsOnFieldsWithManualIndex = "Filtering can be done on data words using value comparators on fields that require manual index input" + ContractReaderDynamicTypedTopicsFilterAndCorrectReturn = "Dynamically typed topics can be used to filter and have type correct in return" + ContractReaderMultipleTopicCanFilterTogether = "Multiple topics can filter together" + ContractReaderFilteringCanBeDoneOnHashedIndexedTopics = "Filtering can be done on indexed topics that get hashed" + ContractReaderBindReturnsErrorOnMissingContractAtAddress = "Bind returns error on missing contract at address" +) + func RunChainComponentsEvmTests[T TestingT[T]](t T, it *EVMChainComponentsInterfaceTester[T]) { RunContractReaderEvmTests[T](t, it) // Add ChainWriter tests here @@ -34,257 +45,295 @@ func RunChainComponentsInLoopEvmTests[T TestingT[T]](t T, it ChainComponentsInte func RunContractReaderEvmTests[T TestingT[T]](t T, it *EVMChainComponentsInterfaceTester[T]) { RunContractReaderInterfaceTests[T](t, it, false) - t.Run("Dynamically typed topics can be used to filter and have type correct in return", func(t T) { - it.Setup(t) - - anyString := "foo" - ctx := it.Helper.Context(t) - - cr := it.GetContractReader(t) - bindings := it.GetBindings(t) - require.NoError(t, cr.Bind(ctx, bindings)) - - type DynamicEvent struct { - Field string - } - SubmitTransactionToCW(t, it, "triggerEventWithDynamicTopic", DynamicEvent{Field: anyString}, bindings[0], types.Unconfirmed) - - input := struct{ Field string }{Field: anyString} - tp := cr.(clcommontypes.ContractTypeProvider) - - readName := types.BoundContract{ - Address: bindings[0].Address, - Name: AnyContractName, - }.ReadIdentifier(triggerWithDynamicTopic) - - output, err := tp.CreateContractType(readName, false) - require.NoError(t, err) - rOutput := reflect.Indirect(reflect.ValueOf(output)) - - require.Eventually(t, func() bool { - return cr.GetLatestValue(ctx, readName, primitives.Unconfirmed, input, output) == nil - }, it.MaxWaitTimeForEvents(), 100*time.Millisecond) - - assert.Equal(t, &anyString, rOutput.FieldByName("Field").Interface()) - topic, err := abi.MakeTopics([]any{anyString}) - require.NoError(t, err) - assert.Equal(t, &topic[0][0], rOutput.FieldByName("FieldHash").Interface()) - }) - - t.Run("Multiple topics can filter together", func(t T) { - it.Setup(t) - ctx := it.Helper.Context(t) - cr := it.GetContractReader(t) - bindings := it.GetBindings(t) - - require.NoError(t, cr.Bind(ctx, bindings)) - - triggerFourTopics(t, it, int32(1), int32(2), int32(3)) - triggerFourTopics(t, it, int32(2), int32(2), int32(3)) - triggerFourTopics(t, it, int32(1), int32(3), int32(3)) - triggerFourTopics(t, it, int32(1), int32(2), int32(4)) - - var bound types.BoundContract - for idx := range bindings { - if bindings[idx].Name == AnyContractName { - bound = bindings[idx] - } - } - - var latest struct{ Field1, Field2, Field3 int32 } - params := struct{ Field1, Field2, Field3 int32 }{Field1: 1, Field2: 2, Field3: 3} - - time.Sleep(it.MaxWaitTimeForEvents()) - - require.NoError(t, cr.GetLatestValue(ctx, bound.ReadIdentifier(triggerWithAllTopics), primitives.Unconfirmed, params, &latest)) - assert.Equal(t, int32(1), latest.Field1) - assert.Equal(t, int32(2), latest.Field2) - assert.Equal(t, int32(3), latest.Field3) - }) - - t.Run("Filtering can be done on indexed topics that get hashed", func(t T) { - it.Setup(t) - - cr := it.GetContractReader(t) - ctx := it.Helper.Context(t) - bindings := it.GetBindings(t) - - require.NoError(t, cr.Bind(ctx, bindings)) - - triggerFourTopicsWithHashed(t, it, "1", [32]uint8{2}, [32]byte{5}) - triggerFourTopicsWithHashed(t, it, "2", [32]uint8{2}, [32]byte{3}) - triggerFourTopicsWithHashed(t, it, "1", [32]uint8{3}, [32]byte{3}) - - var bound types.BoundContract - for idx := range bindings { - if bindings[idx].Name == AnyContractName { - bound = bindings[idx] - } - } - - var latest struct { - Field3 [32]byte - } - params := struct { - Field1 string - Field2 [32]uint8 - Field3 [32]byte - }{Field1: "1", Field2: [32]uint8{2}, Field3: [32]byte{5}} - - time.Sleep(it.MaxWaitTimeForEvents()) - require.NoError(t, cr.GetLatestValue(ctx, bound.ReadIdentifier(triggerWithAllTopicsWithHashed), primitives.Unconfirmed, params, &latest)) - // only checking Field3 topic makes sense since it isn't hashed, to check other fields we'd have to replicate solidity encoding and hashing - assert.Equal(t, [32]uint8{5}, latest.Field3) - }) - - t.Run("Bind returns error on missing contract at address", func(t T) { - it.Setup(t) - - addr := common.BigToAddress(big.NewInt(42)) - reader := it.GetContractReader(t) - - ctx := it.Helper.Context(t) - err := reader.Bind(ctx, []clcommontypes.BoundContract{{Name: AnyContractName, Address: addr.Hex()}}) - - require.ErrorIs(t, err, read.NoContractExistsError{Err: clcommontypes.ErrInternal, Address: addr}) - }) + testCases := []Testcase[T]{ + { + Name: ContractReaderDynamicTypedTopicsFilterAndCorrectReturn, + Test: func(t T) { + it.Setup(t) + + anyString := "foo" + ctx := it.Helper.Context(t) + + cr := it.GetContractReader(t) + bindings := it.GetBindings(t) + require.NoError(t, cr.Bind(ctx, bindings)) + + type DynamicEvent struct { + Field string + } + SubmitTransactionToCW(t, it, "triggerEventWithDynamicTopic", DynamicEvent{Field: anyString}, bindings[0], types.Unconfirmed) + + input := struct{ Field string }{Field: anyString} + tp := cr.(clcommontypes.ContractTypeProvider) + + readName := types.BoundContract{ + Address: bindings[0].Address, + Name: AnyContractName, + }.ReadIdentifier(triggerWithDynamicTopic) + + output, err := tp.CreateContractType(readName, false) + require.NoError(t, err) + rOutput := reflect.Indirect(reflect.ValueOf(output)) + + require.Eventually(t, func() bool { + return cr.GetLatestValue(ctx, readName, primitives.Unconfirmed, input, output) == nil + }, it.MaxWaitTimeForEvents(), 100*time.Millisecond) + + assert.Equal(t, &anyString, rOutput.FieldByName("Field").Interface()) + topic, err := abi.MakeTopics([]any{anyString}) + require.NoError(t, err) + assert.Equal(t, &topic[0][0], rOutput.FieldByName("FieldHash").Interface()) + }, + }, + { + Name: ContractReaderMultipleTopicCanFilterTogether, + Test: func(t T) { + it.Setup(t) + ctx := it.Helper.Context(t) + cr := it.GetContractReader(t) + bindings := it.GetBindings(t) + + require.NoError(t, cr.Bind(ctx, bindings)) + + triggerFourTopics(t, it, int32(1), int32(2), int32(3)) + triggerFourTopics(t, it, int32(2), int32(2), int32(3)) + triggerFourTopics(t, it, int32(1), int32(3), int32(3)) + triggerFourTopics(t, it, int32(1), int32(2), int32(4)) + + var bound types.BoundContract + for idx := range bindings { + if bindings[idx].Name == AnyContractName { + bound = bindings[idx] + } + } + + var latest struct{ Field1, Field2, Field3 int32 } + params := struct{ Field1, Field2, Field3 int32 }{Field1: 1, Field2: 2, Field3: 3} + + time.Sleep(it.MaxWaitTimeForEvents()) + + require.NoError(t, cr.GetLatestValue(ctx, bound.ReadIdentifier(triggerWithAllTopics), primitives.Unconfirmed, params, &latest)) + assert.Equal(t, int32(1), latest.Field1) + assert.Equal(t, int32(2), latest.Field2) + assert.Equal(t, int32(3), latest.Field3) + }, + }, + { + Name: ContractReaderFilteringCanBeDoneOnHashedIndexedTopics, + Test: func(t T) { + it.Setup(t) + + cr := it.GetContractReader(t) + ctx := it.Helper.Context(t) + bindings := it.GetBindings(t) + + require.NoError(t, cr.Bind(ctx, bindings)) + + triggerFourTopicsWithHashed(t, it, "1", [32]uint8{2}, [32]byte{5}) + triggerFourTopicsWithHashed(t, it, "2", [32]uint8{2}, [32]byte{3}) + triggerFourTopicsWithHashed(t, it, "1", [32]uint8{3}, [32]byte{3}) + + var bound types.BoundContract + for idx := range bindings { + if bindings[idx].Name == AnyContractName { + bound = bindings[idx] + } + } + + var latest struct { + Field3 [32]byte + } + params := struct { + Field1 string + Field2 [32]uint8 + Field3 [32]byte + }{Field1: "1", Field2: [32]uint8{2}, Field3: [32]byte{5}} + + time.Sleep(it.MaxWaitTimeForEvents()) + require.NoError(t, cr.GetLatestValue(ctx, bound.ReadIdentifier(triggerWithAllTopicsWithHashed), primitives.Unconfirmed, params, &latest)) + // only checking Field3 topic makes sense since it isn't hashed, to check other fields we'd have to replicate solidity encoding and hashing + assert.Equal(t, [32]uint8{5}, latest.Field3) + }, + }, + { + Name: ContractReaderBindReturnsErrorOnMissingContractAtAddress, + Test: func(t T) { + it.Setup(t) + + addr := common.BigToAddress(big.NewInt(42)) + reader := it.GetContractReader(t) + + ctx := it.Helper.Context(t) + err := reader.Bind(ctx, []clcommontypes.BoundContract{{Name: AnyContractName, Address: addr.Hex()}}) + + require.ErrorIs(t, err, read.NoContractExistsError{Err: clcommontypes.ErrInternal, Address: addr}) + }, + }, + } + RunTests(t, it, testCases) } func RunContractReaderInLoopTests[T TestingT[T]](t T, it ChainComponentsInterfaceTester[T]) { RunContractReaderInterfaceTests[T](t, it, false) - it.Setup(t) - ctx := tests.Context(t) - cr := it.GetContractReader(t) - require.NoError(t, cr.Bind(ctx, it.GetBindings(t))) - bindings := it.GetBindings(t) - boundContract := BindingsByName(bindings, AnyContractName)[0] - require.NoError(t, cr.Bind(ctx, bindings)) - - ts1 := CreateTestStruct[T](0, it) - _ = SubmitTransactionToCW(t, it, MethodTriggeringEvent, ts1, boundContract, types.Unconfirmed) - ts2 := CreateTestStruct[T](15, it) - _ = SubmitTransactionToCW(t, it, MethodTriggeringEvent, ts2, boundContract, types.Unconfirmed) - ts3 := CreateTestStruct[T](35, it) - _ = SubmitTransactionToCW(t, it, MethodTriggeringEvent, ts3, boundContract, types.Unconfirmed) - - t.Run("Filtering can be done on data words using value comparator", func(t T) { - ts := &TestStruct{} - assert.Eventually(t, func() bool { - sequences, err := cr.QueryKey(ctx, boundContract, query.KeyFilter{Key: EventName, Expressions: []query.Expression{ - query.Comparator("OracleID", - primitives.ValueComparator{ - Value: uint8(ts2.OracleID), - Operator: primitives.Eq, - }), - }, - }, query.LimitAndSort{}, ts) - return err == nil && len(sequences) == 1 && reflect.DeepEqual(&ts2, sequences[0].Data) - }, it.MaxWaitTimeForEvents(), time.Millisecond*10) - }) - - t.Run("Filtering can be done on data words using value comparator on a nested field", func(t T) { - ts := &TestStruct{} - assert.Eventually(t, func() bool { - sequences, err := cr.QueryKey(ctx, boundContract, query.KeyFilter{Key: EventName, Expressions: []query.Expression{ - query.Comparator("OracleID", - primitives.ValueComparator{ - Value: uint8(ts2.OracleID), - Operator: primitives.Eq, - }), - query.Comparator("NestedStaticStruct.Inner.IntVal", - primitives.ValueComparator{ - Value: ts2.NestedStaticStruct.Inner.I, - Operator: primitives.Eq, - }), + testCases := []Testcase[T]{ + { + Name: ContractReaderQueryKeyFilterOnDataWordsWithValueComparator, + Test: func(t T) { + ctx := tests.Context(t) + cr := it.GetContractReader(t) + require.NoError(t, cr.Bind(ctx, it.GetBindings(t))) + bindings := it.GetBindings(t) + boundContract := BindingsByName(bindings, AnyContractName)[0] + require.NoError(t, cr.Bind(ctx, bindings)) + + ts1 := CreateTestStruct[T](0, it) + _ = SubmitTransactionToCW(t, it, MethodTriggeringEvent, ts1, boundContract, types.Unconfirmed) + ts2 := CreateTestStruct[T](15, it) + _ = SubmitTransactionToCW(t, it, MethodTriggeringEvent, ts2, boundContract, types.Unconfirmed) + ts3 := CreateTestStruct[T](35, it) + _ = SubmitTransactionToCW(t, it, MethodTriggeringEvent, ts3, boundContract, types.Unconfirmed) + ts := &TestStruct{} + assert.Eventually(t, func() bool { + sequences, err := cr.QueryKey(ctx, boundContract, query.KeyFilter{ + Key: EventName, Expressions: []query.Expression{ + query.Comparator("OracleID", + primitives.ValueComparator{ + Value: uint8(ts2.OracleID), + Operator: primitives.Eq, + }), + }, + }, query.LimitAndSort{}, ts) + return err == nil && len(sequences) == 1 && reflect.DeepEqual(&ts2, sequences[0].Data) + }, it.MaxWaitTimeForEvents(), time.Millisecond*10) }, - }, query.LimitAndSort{}, ts) - return err == nil && len(sequences) == 1 && reflect.DeepEqual(&ts2, sequences[0].Data) - }, it.MaxWaitTimeForEvents(), time.Millisecond*10) - }) - - t.Run("Filtering can be done on data words using value comparator on field that follows a dynamic field", func(t T) { - ts := &TestStruct{} - assert.Eventually(t, func() bool { - sequences, err := cr.QueryKey(ctx, boundContract, query.KeyFilter{Key: EventName, Expressions: []query.Expression{ - query.Comparator("OracleID", - primitives.ValueComparator{ - Value: uint8(ts2.OracleID), - Operator: primitives.Eq, - }), - query.Comparator("BigField", - primitives.ValueComparator{ - Value: ts2.BigField, - Operator: primitives.Eq, - }), + }, + { + Name: ContractReaderQueryKeyOnDataWordsWithValueComparatorOnNestedField, + Test: func(t T) { + ctx := tests.Context(t) + cr := it.GetContractReader(t) + require.NoError(t, cr.Bind(ctx, it.GetBindings(t))) + bindings := it.GetBindings(t) + boundContract := BindingsByName(bindings, AnyContractName)[0] + require.NoError(t, cr.Bind(ctx, bindings)) + + ts1 := CreateTestStruct[T](0, it) + _ = SubmitTransactionToCW(t, it, MethodTriggeringEvent, ts1, boundContract, types.Unconfirmed) + ts2 := CreateTestStruct[T](15, it) + _ = SubmitTransactionToCW(t, it, MethodTriggeringEvent, ts2, boundContract, types.Unconfirmed) + ts3 := CreateTestStruct[T](35, it) + _ = SubmitTransactionToCW(t, it, MethodTriggeringEvent, ts3, boundContract, types.Unconfirmed) + ts := &TestStruct{} + assert.Eventually(t, func() bool { + sequences, err := cr.QueryKey(ctx, boundContract, query.KeyFilter{ + Key: EventName, Expressions: []query.Expression{ + query.Comparator("OracleID", + primitives.ValueComparator{ + Value: uint8(ts2.OracleID), + Operator: primitives.Eq, + }), + query.Comparator("NestedStaticStruct.Inner.IntVal", + primitives.ValueComparator{ + Value: ts2.NestedStaticStruct.Inner.I, + Operator: primitives.Eq, + }), + }, + }, query.LimitAndSort{}, ts) + return err == nil && len(sequences) == 1 && reflect.DeepEqual(&ts2, sequences[0].Data) + }, it.MaxWaitTimeForEvents(), time.Millisecond*10) }, - }, query.LimitAndSort{}, ts) - return err == nil && len(sequences) == 1 && reflect.DeepEqual(&ts2, sequences[0].Data) - }, it.MaxWaitTimeForEvents(), time.Millisecond*10) - }) - - t.Run("Filtering can be done on data words using value comparator on a static field in a dynamic struct that is the first dynamic field", func(t T) { - ts := &TestStruct{} - assert.Eventually(t, func() bool { - sequences, err := cr.QueryKey(ctx, boundContract, query.KeyFilter{Key: EventName, Expressions: []query.Expression{ - query.Comparator("OracleID", - primitives.ValueComparator{ - Value: uint8(ts2.OracleID), - Operator: primitives.Eq, - }), - query.Comparator("NestedDynamicStruct.FixedBytes", - primitives.ValueComparator{ - Value: ts2.NestedDynamicStruct.FixedBytes, - Operator: primitives.Eq, - }), + }, + { + Name: ContractReaderQueryKeyFilterOnDataWordsWithValueComparatorOnDynamicField, + Test: func(t T) { + ctx := tests.Context(t) + cr := it.GetContractReader(t) + require.NoError(t, cr.Bind(ctx, it.GetBindings(t))) + bindings := it.GetBindings(t) + boundContract := BindingsByName(bindings, AnyContractName)[0] + require.NoError(t, cr.Bind(ctx, bindings)) + + ts1 := CreateTestStruct[T](0, it) + _ = SubmitTransactionToCW(t, it, MethodTriggeringEvent, ts1, boundContract, types.Unconfirmed) + ts2 := CreateTestStruct[T](15, it) + _ = SubmitTransactionToCW(t, it, MethodTriggeringEvent, ts2, boundContract, types.Unconfirmed) + ts3 := CreateTestStruct[T](35, it) + _ = SubmitTransactionToCW(t, it, MethodTriggeringEvent, ts3, boundContract, types.Unconfirmed) + ts := &TestStruct{} + assert.Eventually(t, func() bool { + sequences, err := cr.QueryKey(ctx, boundContract, query.KeyFilter{ + Key: EventName, Expressions: []query.Expression{ + query.Comparator("OracleID", + primitives.ValueComparator{ + Value: uint8(ts2.OracleID), + Operator: primitives.Eq, + }), + query.Comparator("BigField", + primitives.ValueComparator{ + Value: ts2.BigField, + Operator: primitives.Eq, + }), + }, + }, query.LimitAndSort{}, ts) + return err == nil && len(sequences) == 1 && reflect.DeepEqual(&ts2, sequences[0].Data) + }, it.MaxWaitTimeForEvents(), time.Millisecond*10) }, - }, query.LimitAndSort{}, ts) - return err == nil && len(sequences) == 1 && reflect.DeepEqual(&ts2, sequences[0].Data) - }, it.MaxWaitTimeForEvents(), time.Millisecond*10) - }) - - t.Run("Filtering can be done on data words using value comparators on fields that require manual index input", func(t T) { - empty12Bytes := [12]byte{} - val1, val2, val3, val4 := uint32(1), uint32(2), uint32(3), uint64(4) - val5, val6, val7 := [32]byte{}, [32]byte{6}, [32]byte{7} - copy(val5[:], append(empty12Bytes[:], 5)) - raw := []byte{9, 8} - - var buf []byte - buf = binary.BigEndian.AppendUint32(buf, val1) - buf = binary.BigEndian.AppendUint32(buf, val2) - buf = binary.BigEndian.AppendUint32(buf, val3) - buf = binary.BigEndian.AppendUint64(buf, val4) - dataWordOnChainValueToQuery := buf - - resExpected := append(buf, common.LeftPadBytes(val5[:], 32)...) - resExpected = append(resExpected, common.LeftPadBytes(val6[:], 32)...) - resExpected = append(resExpected, common.LeftPadBytes(val7[:], 32)...) - resExpected = append(resExpected, raw...) - - type eventResAsStruct struct { - Message *[]uint8 - } - wrapExpectedRes := eventResAsStruct{Message: &resExpected} - - // emit the one we want to search for and a couple of random ones to confirm that filtering works - triggerStaticBytes(t, it, val1, val2, val3, val4, val5, val6, val7, raw) - triggerStaticBytes(t, it, 1337, 7331, 4747, val4, val5, val6, val7, raw) - triggerStaticBytes(t, it, 7331, 4747, 1337, val4, val5, val6, val7, raw) - triggerStaticBytes(t, it, 4747, 1337, 7331, val4, val5, val6, val7, raw) - - assert.Eventually(t, func() bool { - sequences, err := cr.QueryKey(ctx, boundContract, query.KeyFilter{Key: staticBytesEventName, Expressions: []query.Expression{ - query.Comparator("msgTransmitterEvent", - primitives.ValueComparator{ - Value: dataWordOnChainValueToQuery, - Operator: primitives.Eq, - }), + }, + { + Name: ContractReaderQueryKeyFilteringOnDataWordsUsingValueComparatorsOnFieldsWithManualIndex, + Test: func(t T) { + ctx := tests.Context(t) + cr := it.GetContractReader(t) + require.NoError(t, cr.Bind(ctx, it.GetBindings(t))) + bindings := it.GetBindings(t) + boundContract := BindingsByName(bindings, AnyContractName)[0] + require.NoError(t, cr.Bind(ctx, bindings)) + empty12Bytes := [12]byte{} + val1, val2, val3, val4 := uint32(1), uint32(2), uint32(3), uint64(4) + val5, val6, val7 := [32]byte{}, [32]byte{6}, [32]byte{7} + copy(val5[:], append(empty12Bytes[:], 5)) + raw := []byte{9, 8} + + var resExpected []byte + resExpected = binary.BigEndian.AppendUint32(resExpected, val1) + resExpected = binary.BigEndian.AppendUint32(resExpected, val2) + resExpected = binary.BigEndian.AppendUint32(resExpected, val3) + resExpected = binary.BigEndian.AppendUint64(resExpected, val4) + dataWordOnChainValueToQuery := resExpected + + resExpected = append(resExpected, common.LeftPadBytes(val5[:], 32)...) + resExpected = append(resExpected, common.LeftPadBytes(val6[:], 32)...) + resExpected = append(resExpected, common.LeftPadBytes(val7[:], 32)...) + resExpected = append(resExpected, raw...) + + type eventResAsStruct struct { + Message *[]uint8 + } + wrapExpectedRes := eventResAsStruct{Message: &resExpected} + + // emit the one we want to search for and a couple of random ones to confirm that filtering works + triggerStaticBytes(t, it, val1, val2, val3, val4, val5, val6, val7, raw) + triggerStaticBytes(t, it, 1337, 7331, 4747, val4, val5, val6, val7, raw) + triggerStaticBytes(t, it, 7331, 4747, 1337, val4, val5, val6, val7, raw) + triggerStaticBytes(t, it, 4747, 1337, 7331, val4, val5, val6, val7, raw) + + assert.Eventually(t, func() bool { + sequences, err := cr.QueryKey(ctx, boundContract, query.KeyFilter{ + Key: staticBytesEventName, Expressions: []query.Expression{ + query.Comparator("msgTransmitterEvent", + primitives.ValueComparator{ + Value: dataWordOnChainValueToQuery, + Operator: primitives.Eq, + }), + }, + }, query.LimitAndSort{}, eventResAsStruct{}) + return err == nil && len(sequences) == 1 && reflect.DeepEqual(wrapExpectedRes, sequences[0].Data) + }, it.MaxWaitTimeForEvents(), time.Millisecond*10) }, - }, query.LimitAndSort{}, eventResAsStruct{}) - return err == nil && len(sequences) == 1 && reflect.DeepEqual(wrapExpectedRes, sequences[0].Data) - }, it.MaxWaitTimeForEvents(), time.Millisecond*10) - }) + }, + } + RunTests(t, it, testCases) } func triggerFourTopics[T TestingT[T]](t T, it *EVMChainComponentsInterfaceTester[T], i1, i2, i3 int32) { diff --git a/deployment/go.mod b/deployment/go.mod index af4223b410e..320e7670d72 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -24,7 +24,7 @@ require ( github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240926212305-a6deabdfce86 github.com/smartcontractkit/chain-selectors v1.0.27 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241111184621-c61aebee0af9 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 @@ -405,7 +405,7 @@ require ( github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 // indirect - github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241104202120-39cabce465f6 // indirect + github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 // indirect github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0 // indirect github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.5 // indirect diff --git a/deployment/go.sum b/deployment/go.sum index 27a0e15dcd6..77809c8059b 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1384,8 +1384,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 h1:BeLnOf2KKQpJj9nzfnE7QEg9ZqJ2jy/sbpNYVixVM2Y= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241111184621-c61aebee0af9 h1:xjrbuLW28nJ661Hu9dodcCQm7ElB5AWnZjmqGiGLNZg= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241111184621-c61aebee0af9/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 h1:yJNBWCdNL/X8+wEs3TGTBe9gssMmw5FTFxxrlo+0mVo= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f/go.mod h1:wHtwSR3F1CQSJJZDQKuqaqFYnvkT+kMyget7dl8Clvo= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e h1:JiETqdNM0bktAUGMc62COwXIaw3rR3M77Me6bBLG0Fg= @@ -1396,8 +1396,8 @@ github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 h1:1xTm8UGeD github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 h1:PBUaFfPLm+Efq7H9kdfGBivH+QhJ6vB5EZTR/sCZsxI= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241104202120-39cabce465f6 h1:YsE0uS6S10oAWnFbjNDc7tN9JrWYjvyqMnTSbTSgl00= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241104202120-39cabce465f6/go.mod h1:iZugccCLpPWtcGiR/8gurre2j3RtyKnqd1FcVR0NzQw= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 h1:blu++xbH/NSb+ii5hI4jczwojZ7Hc1ERXjpt/krYy9c= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930/go.mod h1:mGmRvlk54ufCufV4EBWizOGtXoXfePoFAuYEVC8EwdY= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 h1:B4DFdk6MGcQnoCjjMBCx7Z+GWQpxRWJ4O8W/dVJyWGA= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8/go.mod h1:WkBqgBo+g34Gm5vWkDDl8Fh3Mzd7bF5hXp7rryg0t5o= github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 h1:T0kbw07Vb6xUyA9MIJZfErMgWseWi1zf7cYvRpoq7ug= diff --git a/go.mod b/go.mod index 7e74074dbe2..28d6920bcd9 100644 --- a/go.mod +++ b/go.mod @@ -77,12 +77,12 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.27 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241111184621-c61aebee0af9 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e github.com/smartcontractkit/chainlink-feeds v0.1.1 github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 - github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241104202120-39cabce465f6 + github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 github.com/smartcontractkit/libocr v0.0.0-20241007185508-adbe57025f12 github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de diff --git a/go.sum b/go.sum index 36be5a0d25d..de6fdf996f2 100644 --- a/go.sum +++ b/go.sum @@ -1078,8 +1078,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 h1:BeLnOf2KKQpJj9nzfnE7QEg9ZqJ2jy/sbpNYVixVM2Y= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241111184621-c61aebee0af9 h1:xjrbuLW28nJ661Hu9dodcCQm7ElB5AWnZjmqGiGLNZg= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241111184621-c61aebee0af9/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 h1:yJNBWCdNL/X8+wEs3TGTBe9gssMmw5FTFxxrlo+0mVo= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f/go.mod h1:wHtwSR3F1CQSJJZDQKuqaqFYnvkT+kMyget7dl8Clvo= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e h1:JiETqdNM0bktAUGMc62COwXIaw3rR3M77Me6bBLG0Fg= @@ -1088,8 +1088,8 @@ github.com/smartcontractkit/chainlink-feeds v0.1.1 h1:JzvUOM/OgGQA1sOqTXXl52R6An github.com/smartcontractkit/chainlink-feeds v0.1.1/go.mod h1:55EZ94HlKCfAsUiKUTNI7QlE/3d3IwTlsU3YNa/nBb4= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 h1:PBUaFfPLm+Efq7H9kdfGBivH+QhJ6vB5EZTR/sCZsxI= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241104202120-39cabce465f6 h1:YsE0uS6S10oAWnFbjNDc7tN9JrWYjvyqMnTSbTSgl00= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241104202120-39cabce465f6/go.mod h1:iZugccCLpPWtcGiR/8gurre2j3RtyKnqd1FcVR0NzQw= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 h1:blu++xbH/NSb+ii5hI4jczwojZ7Hc1ERXjpt/krYy9c= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930/go.mod h1:mGmRvlk54ufCufV4EBWizOGtXoXfePoFAuYEVC8EwdY= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 h1:B4DFdk6MGcQnoCjjMBCx7Z+GWQpxRWJ4O8W/dVJyWGA= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8/go.mod h1:WkBqgBo+g34Gm5vWkDDl8Fh3Mzd7bF5hXp7rryg0t5o= github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12ijqMM9tvYVEm+nR826WsrNi6zCKpwBhuApq127wHs= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index eb549e9b271..985710ad69a 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -37,7 +37,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.27 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241111184621-c61aebee0af9 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.2 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 @@ -45,7 +45,7 @@ require ( github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.5 github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.2 github.com/smartcontractkit/chainlink/deployment v0.0.0-00010101000000-000000000000 - github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 + github.com/smartcontractkit/chainlink/v2 v2.14.0-mercury-20240807.0.20241106193309-5560cd76211a github.com/smartcontractkit/libocr v0.0.0-20241007185508-adbe57025f12 github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.9.0 @@ -418,7 +418,7 @@ require ( github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 // indirect - github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241104202120-39cabce465f6 // indirect + github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 // indirect github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index ee39a38ebe8..a5c2fa81a44 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1405,8 +1405,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 h1:BeLnOf2KKQpJj9nzfnE7QEg9ZqJ2jy/sbpNYVixVM2Y= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241111184621-c61aebee0af9 h1:xjrbuLW28nJ661Hu9dodcCQm7ElB5AWnZjmqGiGLNZg= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241111184621-c61aebee0af9/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 h1:yJNBWCdNL/X8+wEs3TGTBe9gssMmw5FTFxxrlo+0mVo= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f/go.mod h1:wHtwSR3F1CQSJJZDQKuqaqFYnvkT+kMyget7dl8Clvo= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e h1:JiETqdNM0bktAUGMc62COwXIaw3rR3M77Me6bBLG0Fg= @@ -1417,8 +1417,8 @@ github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 h1:1xTm8UGeD github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 h1:PBUaFfPLm+Efq7H9kdfGBivH+QhJ6vB5EZTR/sCZsxI= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241104202120-39cabce465f6 h1:YsE0uS6S10oAWnFbjNDc7tN9JrWYjvyqMnTSbTSgl00= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241104202120-39cabce465f6/go.mod h1:iZugccCLpPWtcGiR/8gurre2j3RtyKnqd1FcVR0NzQw= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 h1:blu++xbH/NSb+ii5hI4jczwojZ7Hc1ERXjpt/krYy9c= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930/go.mod h1:mGmRvlk54ufCufV4EBWizOGtXoXfePoFAuYEVC8EwdY= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 h1:B4DFdk6MGcQnoCjjMBCx7Z+GWQpxRWJ4O8W/dVJyWGA= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8/go.mod h1:WkBqgBo+g34Gm5vWkDDl8Fh3Mzd7bF5hXp7rryg0t5o= github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.2 h1:GDGrC5OGiV0RyM1znYWehSQXyZQWTOzrEeJRYmysPCE= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 4f4f315082b..539e7a2bccc 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -17,13 +17,13 @@ require ( github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.33.0 github.com/slack-go/slack v0.15.0 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241111184621-c61aebee0af9 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.5 github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.2 github.com/smartcontractkit/chainlink/deployment v0.0.0-00010101000000-000000000000 github.com/smartcontractkit/chainlink/integration-tests v0.0.0-20241030133659-9ec788e78b4f - github.com/smartcontractkit/chainlink/v2 v2.9.0-beta0.0.20240216210048-da02459ddad8 + github.com/smartcontractkit/chainlink/v2 v2.14.0-mercury-20240807.0.20241106193309-5560cd76211a github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de github.com/stretchr/testify v1.9.0 github.com/wiremock/go-wiremock v1.9.0 @@ -425,7 +425,7 @@ require ( github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 // indirect - github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241104202120-39cabce465f6 // indirect + github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 // indirect github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0 // indirect github.com/smartcontractkit/libocr v0.0.0-20241007185508-adbe57025f12 // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index a201343efbf..83d8b0ee21f 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1394,8 +1394,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 h1:BeLnOf2KKQpJj9nzfnE7QEg9ZqJ2jy/sbpNYVixVM2Y= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241111184621-c61aebee0af9 h1:xjrbuLW28nJ661Hu9dodcCQm7ElB5AWnZjmqGiGLNZg= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241111184621-c61aebee0af9/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 h1:yJNBWCdNL/X8+wEs3TGTBe9gssMmw5FTFxxrlo+0mVo= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f/go.mod h1:wHtwSR3F1CQSJJZDQKuqaqFYnvkT+kMyget7dl8Clvo= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e h1:JiETqdNM0bktAUGMc62COwXIaw3rR3M77Me6bBLG0Fg= @@ -1404,8 +1404,8 @@ github.com/smartcontractkit/chainlink-feeds v0.1.1 h1:JzvUOM/OgGQA1sOqTXXl52R6An github.com/smartcontractkit/chainlink-feeds v0.1.1/go.mod h1:55EZ94HlKCfAsUiKUTNI7QlE/3d3IwTlsU3YNa/nBb4= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 h1:PBUaFfPLm+Efq7H9kdfGBivH+QhJ6vB5EZTR/sCZsxI= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241104202120-39cabce465f6 h1:YsE0uS6S10oAWnFbjNDc7tN9JrWYjvyqMnTSbTSgl00= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241104202120-39cabce465f6/go.mod h1:iZugccCLpPWtcGiR/8gurre2j3RtyKnqd1FcVR0NzQw= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 h1:blu++xbH/NSb+ii5hI4jczwojZ7Hc1ERXjpt/krYy9c= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930/go.mod h1:mGmRvlk54ufCufV4EBWizOGtXoXfePoFAuYEVC8EwdY= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 h1:B4DFdk6MGcQnoCjjMBCx7Z+GWQpxRWJ4O8W/dVJyWGA= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8/go.mod h1:WkBqgBo+g34Gm5vWkDDl8Fh3Mzd7bF5hXp7rryg0t5o= github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.2 h1:GDGrC5OGiV0RyM1znYWehSQXyZQWTOzrEeJRYmysPCE= From 11e4b6faf5c690986bc98cf284160f610fabe716 Mon Sep 17 00:00:00 2001 From: Connor Stein Date: Tue, 12 Nov 2024 17:13:40 -0500 Subject: [PATCH 02/14] deployment/README update (#15194) * REAMDE update * Start FAQ --- deployment/README.md | 145 +++++++++++++++++++++++++++++-------------- 1 file changed, 97 insertions(+), 48 deletions(-) diff --git a/deployment/README.md b/deployment/README.md index fa6c87cf527..723397edc1c 100644 --- a/deployment/README.md +++ b/deployment/README.md @@ -5,6 +5,79 @@ dependencies. The environment abstractions allow for complex and critical deployment/configuration logic to be tested against ephemeral environments and then exposed for use in persistent environments like testnet/mainnet. +## Table of Contents +- [Address Book](##Address-Book) +- [View](##View) +- [Environment](##Environment) +- [Job Distributor](##Job-Distributor) +- [Changesets](##Changesets) +- [Directory Structure](##Directory-Structure) +- [Integration Testing](##Integration-Testing) +- [FAQ](##FAQ) + +## Address Book +An [address book](https://github.com/smartcontractkit/chainlink/blob/develop/deployment/address_book.go#L79) represents +a set of versioned, onchain addresses for a given product across all blockchain families. The primary key +is a family agnostic [chain-selector](https://github.com/smartcontractkit/chain-selectors) chain identifier combined with a unique +address within the chain. Anything which is globally addressable on the chain can be used for the address field, for example +EVM smart contract addresses, Aptos objectIDs/accounts, Solana programs/accounts etc. +The address book holds the minimum amount of information to derive the onchain state of the system from +the chains themselves as a source of truth. + +It is recommended that you define a State struct holding Go bindings for each onchain component and author a +translation layer between the address book and the state struct. Think of it like an expanded/wrapped address book +which enables read/writing to those objects. See an example [here](https://github.com/smartcontractkit/chainlink/blob/develop/deployment/ccip/state.go#L205). +This way, given an address book, you can easily read/write state or generate a [View](##View). +Note that for contract upgrades its expected that you would have versioned field names in the State struct until the v1 is fully removed, this +way you can easily test upgrades and support multiple versions of contracts. + +## View +A [view](https://github.com/smartcontractkit/chainlink/blob/develop/deployment/changeset.go#L35) is a function which +serializes the state of the system into a JSON object. This is useful for exporting to other systems (like a UI, docs, DS&A etc). +You can generate it however you see fit, but a straightforward way is to translate +the address book into a State structure and then serialize that using Go bindings. + +## Environment +An [environment](https://github.com/smartcontractkit/chainlink/blob/develop/deployment/environment.go#L71) represents +the existing state of the system including onchain (including non-EVMs) and offchain components. Conceptually it contains +a set of pointers and interfaces to dereference those pointers from the source of truth. +The onchain "pointers" are an address book of existing addresses and the Chains field holds +clients to read/write to those addresses. The offchain "pointers" are a set of nodeIDs and +the Offchain client (interface to the [job-distributor](##Job Distributor)) to read/write to them. + +## Job Distributor +The job distributor is a product agnostic in-house service for +managing jobs and CL nodes. It is required to use if you want to +manage your system through chainlink deployments. + +## Changsets +A [changeset](https://github.com/smartcontractkit/chainlink/blob/develop/deployment/changeset.go#L21) is a +Go function which describes a set of changes to be applied to an environment given some configuration: +```go +type ChangeSet func(e Environment, config interface{}) (ChangesetOutput, error) +``` +For example, changesets might include: +- Deploying a new contract +- Deploying 2 contracts where the second contract depends on the first's address +- Deploying a contract and creating a job spec where the job spec points to the deployed contract address +- Creating an MCMS proposal to set a billing parameter on a contract +- Deploying a full system from scratch + - Mainly useful for integration tests +- Modifying a contract not yet owned by MCMS via the deployer key + +Once sufficient changesets are built and tested, the ongoing maintenance +of a product should be just invoking existing changesets with new configuration. +The configuration can be environment/product specific, for example +specific chain addresses, chain selectors, data sources etc. The outputs are +a set of diff artifacts to be applied to the environment (MCMS proposals, job specs, addresses created). +You can use the changeset for side effects only and return no artifacts. +An example would be making an onchain change with the deployer key instead of an MCMS proposal, +however that should generally be uncommon. Usually we'd expect an initial deployment to produce +a set of addresses and job specs (likely pointing to those addresses) and then from that point forward +we'd expect to use MCMS proposals to make changes. + +TODO: Add various examples in deployment/example. + ## Directory structure /deployment @@ -27,51 +100,27 @@ and then exposed for use in persistent environments like testnet/mainnet. contracts (like MCMS, LinkToken etc) which can be shared by products. -/deployment/ccip -- package name `ccipdeployment` -- Files and tests per product deployment/configuration workflows -- Tests can use deployment/memory for fast integration testing -- TODO: System state representation is defined here, need to define - an interface to comply with for all products. - -/deployment/ccip/changeset -- package name `changeset` imported as `ccipchangesets` -- These function like scripts describing state transitions - you wish to apply to _persistent_ environments like testnet/mainnet -- They should be go functions where the first argument is an - environment and the second argument is a config struct which can be unique to the - changeset. The return value should be a `deployment.ChangesetOutput` and an error. - -- `do_something.go` - ```Go - func DoSomethingChangeSet(env deployment.Environment, c ccipdeployment.Config) (deployment.ChangesetOutput, error) - { - // Deploy contracts, generate MCMS proposals, generate - // job specs according to contracts etc. - return deployment.ChangesetOutput{}, nil - } - ``` - -- `do_something_test.go` - ```Go - func TestDoSomething(t *testing.T) - { - // Set up memory env - // DoSomethingChangeSet function - // Take the artifacts from ChangeSet output - // Apply them to the memory env - // Send traffic, run assertions etc. - } - ``` -- Changesets are exposed and applied via a different repo. - -/deployment/llo -- package name `llodeployment` -- Similar to /deploymet/ccip, these are product-specific deployment/configuration workflows -- Tests can use deployment/memory for fast integration testing - -/deployment/llo/changeset -- package name `changeset` imported as `llochangesets` -- Similar to deployment/ccip/changesets -- These function like scripts describing state transitions - you wish to apply to _persistent_ environments like testnet/mainnet +/deployment/ +- package name `deployment` +- Internal building blocks for changesets +- TODO: can we make this `internal`? + +/deployment//changeset +- Think of this as the public API for deployment and configuration +of your product. +- All the changesets should have an associated test using a memory or devenv +environment. +- package name `changeset` imported as `changeset` + +## Integration testing +Integration tests should live in the integration-tests/go.mod module and leverage +the deployment module for product deployment and configuration. The integration tests +should only depend on deployment//changeset and deployment/environment. + +## FAQ +### Should my changeset be idempotent? +It depends on the use case and is at your discretion. In many cases +it would be beneficial to make it idempotent so that if anything goes wrong +you can re-run it without side effects. However, it's possible that the onchain contract +design doesn't allow for idempotency so in that case you'd have to be prepared +with recovery changesets if something goes wrong as re-running it would not be an option. From 1f7a435796907d5524b0365b1ed5e5b2182c7813 Mon Sep 17 00:00:00 2001 From: Rens Rooimans Date: Wed, 13 Nov 2024 00:03:33 +0100 Subject: [PATCH 03/14] CCIP-4177 New snapshot regex & mark fuzz tests with Fuzz (#15151) * new snap regex & mark fuzz tests * fix ci regex * rename fuzz --- .github/workflows/solidity-foundry.yml | 2 +- contracts/.changeset/dull-otters-behave.md | 5 + contracts/GNUmakefile | 4 +- contracts/gas-snapshots/ccip.gas-snapshot | 191 +++++++++--------- contracts/gas-snapshots/keystone.gas-snapshot | 76 ------- .../operatorforwarder.gas-snapshot | 12 +- contracts/gas-snapshots/shared.gas-snapshot | 10 +- .../EtherSenderReceiverTest.ccipReceive.t.sol | 2 +- .../EtherSenderReceiverTest.ccipSend.t.sol | 4 +- ...rSenderReceiverTest.validatedMessage.t.sol | 4 +- .../PingPong/PingPong.setCounterpart.t.sol | 2 +- .../PingPong.setCounterpartAddress.t.sol | 2 +- ...PingPong.setCounterpartChainSelector.t.sol | 2 +- ...eeQuoter.applyDestChainConfigUpdates.t.sol | 2 +- ...plyPremiumMultiplierWeiPerEthUpdates.t.sol | 2 +- ...r.applyTokenTransferFeeConfigUpdates.t.sol | 2 +- .../FeeQuoter.convertTokenAmount.t.sol | 2 +- .../FeeQuoter.getDataAvailabilityCost.t.sol | 4 +- .../FeeQuoter.getTokenTransferCost.t.sol | 2 +- .../feeQuoter/FeeQuoter.getValidatedFee.t.sol | 2 +- .../test/libraries/MerkleMultiProof.t.sol | 10 +- .../MultiOCR3Base.setOCR3Configs.t.sol | 2 +- .../MultiOCR3Base.transmit.t.sol | 2 +- ...ffRamp.applySourceChainConfigUpdates.t.sol | 2 +- .../OffRamp/OffRamp.executeSingleReport.t.sol | 2 +- .../OffRamp/OffRamp.getExecutionState.t.sol | 2 +- .../OffRamp/OffRamp.releaseOrMintTokens.t.sol | 2 +- .../OnRamp/OnRamp.forwardFromRouter.t.sol | 2 +- .../OnRamp/OnRamp.withdrawFeeTokens.t.sol | 2 +- .../LockReleaseTokenPool.lockOrBurn.t.sol | 2 +- ...ockReleaseTokenPool.provideLiquidity.t.sol | 4 +- .../LockReleaseTokenPool.releaseOrMint.t.sol | 2 +- ...ReleaseTokenPool.withdrawalLiquidity.t.sol | 2 +- .../TokenPool.setChainRateLimiterConfig.t.sol | 2 +- .../USDCTokenPool.lockOrBurn.t.sol | 4 +- .../USDCTokenPool.releaseOrMint.t.sol | 2 +- .../USDCTokenPool.setDomains.t.sol | 2 +- .../USDCTokenPool.validateMessage.t.sol | 2 +- .../Router/Router.applyRampUpdates.t.sol | 4 +- .../Router/Router.setWrappedNative.t.sol | 2 +- ...AdminRegistry.getAllConfiguredTokens.t.sol | 2 +- ...enAdminRegistry.proposeAdministrator.t.sol | 2 +- .../operatorforwarder/test/Forwarder.t.sol | 4 +- .../operatorforwarder/test/operator.t.sol | 4 +- .../shared/test/call/CallWithExactGas.t.sol | 6 +- 45 files changed, 163 insertions(+), 241 deletions(-) create mode 100644 contracts/.changeset/dull-otters-behave.md diff --git a/.github/workflows/solidity-foundry.yml b/.github/workflows/solidity-foundry.yml index fcd8912c3e7..dd331730405 100644 --- a/.github/workflows/solidity-foundry.yml +++ b/.github/workflows/solidity-foundry.yml @@ -256,7 +256,7 @@ jobs: || needs.changes.outputs.non_src_changes == 'true') && matrix.product.setup.run-gas-snapshot }} run: | - forge snapshot --nmt "test_?Fuzz_\w{1,}?" --check gas-snapshots/${{ matrix.product.name }}.gas-snapshot + forge snapshot --nmt "test?(Fuzz|Fork|.*_RevertWhen)_.*" --check gas-snapshots/${{ matrix.product.name }}.gas-snapshot id: snapshot working-directory: contracts env: diff --git a/contracts/.changeset/dull-otters-behave.md b/contracts/.changeset/dull-otters-behave.md new file mode 100644 index 00000000000..00b45157a51 --- /dev/null +++ b/contracts/.changeset/dull-otters-behave.md @@ -0,0 +1,5 @@ +--- +'@chainlink/contracts': patch +--- + +#internal rework the regex for snapshot inclusion diff --git a/contracts/GNUmakefile b/contracts/GNUmakefile index 4d47fa05ba5..5fae1cdf927 100644 --- a/contracts/GNUmakefile +++ b/contracts/GNUmakefile @@ -16,11 +16,11 @@ ALL_FOUNDRY_PRODUCTS = ccip functions keystone l2ep liquiditymanager llo-feeds o # a static fuzz seed by default, flaky gas results per platform are still observed. .PHONY: snapshot snapshot: ## Make a snapshot for a specific product. - export FOUNDRY_PROFILE=$(FOUNDRY_PROFILE) && forge snapshot --nmt "test_?Fuzz_\w{1,}?" --snap gas-snapshots/$(FOUNDRY_PROFILE).gas-snapshot + export FOUNDRY_PROFILE=$(FOUNDRY_PROFILE) && forge snapshot --nmt "test?(Fuzz|Fork|.*_RevertWhen)_.*" --snap gas-snapshots/$(FOUNDRY_PROFILE).gas-snapshot .PHONY: snapshot-diff snapshot-diff: ## Make a snapshot for a specific product. - export FOUNDRY_PROFILE=$(FOUNDRY_PROFILE) && forge snapshot --nmt "test_?Fuzz_\w{1,}?" --diff gas-snapshots/$(FOUNDRY_PROFILE).gas-snapshot + export FOUNDRY_PROFILE=$(FOUNDRY_PROFILE) && forge snapshot --nmt "test?(Fuzz|Fork|.*_RevertWhen)_.*" --diff gas-snapshots/$(FOUNDRY_PROFILE).gas-snapshot .PHONY: snapshot-all diff --git a/contracts/gas-snapshots/ccip.gas-snapshot b/contracts/gas-snapshots/ccip.gas-snapshot index 18ea50101d4..54b9cdf22d7 100644 --- a/contracts/gas-snapshots/ccip.gas-snapshot +++ b/contracts/gas-snapshots/ccip.gas-snapshot @@ -69,11 +69,11 @@ CCIPHome_supportsInterface:test_supportsInterface_success() (gas: 9885) DefensiveExampleTest:test_HappyPath_Success() (gas: 200473) DefensiveExampleTest:test_Recovery() (gas: 424876) E2E:test_E2E_3MessagesMMultiOffRampSuccess_gas() (gas: 1519829) -EtherSenderReceiverTest_ccipReceive:test_ccipReceive_fallbackToWethTransfer() (gas: 96962) +EtherSenderReceiverTest_ccipReceive:test_ccipReceive_fallbackToWethTransfer() (gas: 96980) EtherSenderReceiverTest_ccipReceive:test_ccipReceive_happyPath() (gas: 49812) -EtherSenderReceiverTest_ccipReceive:test_ccipReceive_wrongToken() (gas: 17457) +EtherSenderReceiverTest_ccipReceive:test_ccipReceive_wrongToken() (gas: 17479) EtherSenderReceiverTest_ccipReceive:test_ccipReceive_wrongTokenAmount() (gas: 15753) -EtherSenderReceiverTest_ccipSend:test_ccipSend_reverts_insufficientFee_feeToken() (gas: 99930) +EtherSenderReceiverTest_ccipSend:test_ccipSend_reverts_insufficientFee_feeToken() (gas: 99953) EtherSenderReceiverTest_ccipSend:test_ccipSend_reverts_insufficientFee_native() (gas: 76182) EtherSenderReceiverTest_ccipSend:test_ccipSend_reverts_insufficientFee_weth() (gas: 99974) EtherSenderReceiverTest_ccipSend:test_ccipSend_success_feeToken() (gas: 145007) @@ -86,10 +86,10 @@ EtherSenderReceiverTest_validateFeeToken:test_validateFeeToken_reverts_feeToken_ EtherSenderReceiverTest_validateFeeToken:test_validateFeeToken_valid_feeToken() (gas: 16682) EtherSenderReceiverTest_validateFeeToken:test_validateFeeToken_valid_native() (gas: 16615) EtherSenderReceiverTest_validatedMessage:test_validatedMessage_dataOverwrittenToMsgSender() (gas: 25456) -EtherSenderReceiverTest_validatedMessage:test_validatedMessage_emptyDataOverwrittenToMsgSender() (gas: 25351) +EtherSenderReceiverTest_validatedMessage:test_validatedMessage_emptyDataOverwrittenToMsgSender() (gas: 25373) EtherSenderReceiverTest_validatedMessage:test_validatedMessage_invalidTokenAmounts() (gas: 17969) EtherSenderReceiverTest_validatedMessage:test_validatedMessage_tokenOverwrittenToWeth() (gas: 25328) -EtherSenderReceiverTest_validatedMessage:test_validatedMessage_validMessage_extraArgs() (gas: 26392) +EtherSenderReceiverTest_validatedMessage:test_validatedMessage_validMessage_extraArgs() (gas: 26348) FactoryBurnMintERC20_approve:test_Approve_Success() (gas: 55819) FactoryBurnMintERC20_approve:test_InvalidAddress_Reverts() (gas: 10703) FactoryBurnMintERC20_burn:test_BasicBurn_Success() (gas: 172464) @@ -119,31 +119,31 @@ FactoryBurnMintERC20_mint:test_SenderNotMinter_Reverts() (gas: 11405) FactoryBurnMintERC20_supportsInterface:test_SupportsInterface_Success() (gas: 11538) FactoryBurnMintERC20_transfer:test_InvalidAddress_Reverts() (gas: 10701) FactoryBurnMintERC20_transfer:test_Transfer_Success() (gas: 42482) -FeeQuoter_applyDestChainConfigUpdates:test_InvalidChainFamilySelector_Revert() (gas: 16846) -FeeQuoter_applyDestChainConfigUpdates:test_InvalidDestChainConfigDestChainSelectorEqZero_Revert() (gas: 16759) -FeeQuoter_applyDestChainConfigUpdates:test_applyDestChainConfigUpdatesDefaultTxGasLimitEqZero_Revert() (gas: 16813) -FeeQuoter_applyDestChainConfigUpdates:test_applyDestChainConfigUpdatesDefaultTxGasLimitGtMaxPerMessageGasLimit_Revert() (gas: 41217) -FeeQuoter_applyDestChainConfigUpdates:test_applyDestChainConfigUpdatesZeroInput_Success() (gas: 12452) -FeeQuoter_applyDestChainConfigUpdates:test_applyDestChainConfigUpdates_Success() (gas: 140665) +FeeQuoter_applyDestChainConfigUpdates:test_InvalidChainFamilySelector_Revert() (gas: 16824) +FeeQuoter_applyDestChainConfigUpdates:test_InvalidDestChainConfigDestChainSelectorEqZero_Revert() (gas: 16737) +FeeQuoter_applyDestChainConfigUpdates:test_applyDestChainConfigUpdatesDefaultTxGasLimitEqZero_Revert() (gas: 16791) +FeeQuoter_applyDestChainConfigUpdates:test_applyDestChainConfigUpdatesDefaultTxGasLimitGtMaxPerMessageGasLimit_Revert() (gas: 41195) +FeeQuoter_applyDestChainConfigUpdates:test_applyDestChainConfigUpdatesZeroInput_Success() (gas: 12541) +FeeQuoter_applyDestChainConfigUpdates:test_applyDestChainConfigUpdates_Success() (gas: 140643) FeeQuoter_applyFeeTokensUpdates:test_ApplyFeeTokensUpdates_Success() (gas: 162508) FeeQuoter_applyFeeTokensUpdates:test_OnlyCallableByOwner_Revert() (gas: 12241) FeeQuoter_applyPremiumMultiplierWeiPerEthUpdates:test_OnlyCallableByOwnerOrAdmin_Revert() (gas: 11564) -FeeQuoter_applyPremiumMultiplierWeiPerEthUpdates:test_applyPremiumMultiplierWeiPerEthUpdatesMultipleTokens_Success() (gas: 54882) -FeeQuoter_applyPremiumMultiplierWeiPerEthUpdates:test_applyPremiumMultiplierWeiPerEthUpdatesSingleToken_Success() (gas: 45290) -FeeQuoter_applyPremiumMultiplierWeiPerEthUpdates:test_applyPremiumMultiplierWeiPerEthUpdatesZeroInput() (gas: 12434) +FeeQuoter_applyPremiumMultiplierWeiPerEthUpdates:test_applyPremiumMultiplierWeiPerEthUpdatesMultipleTokens_Success() (gas: 54904) +FeeQuoter_applyPremiumMultiplierWeiPerEthUpdates:test_applyPremiumMultiplierWeiPerEthUpdatesSingleToken_Success() (gas: 45323) +FeeQuoter_applyPremiumMultiplierWeiPerEthUpdates:test_applyPremiumMultiplierWeiPerEthUpdatesZeroInput() (gas: 12456) FeeQuoter_applyTokenTransferFeeConfigUpdates:test_ApplyTokenTransferFeeConfig_Success() (gas: 88930) FeeQuoter_applyTokenTransferFeeConfigUpdates:test_ApplyTokenTransferFeeZeroInput() (gas: 13324) -FeeQuoter_applyTokenTransferFeeConfigUpdates:test_InvalidDestBytesOverhead_Revert() (gas: 17501) -FeeQuoter_applyTokenTransferFeeConfigUpdates:test_OnlyCallableByOwnerOrAdmin_Revert() (gas: 12305) +FeeQuoter_applyTokenTransferFeeConfigUpdates:test_InvalidDestBytesOverhead_Revert() (gas: 17413) +FeeQuoter_applyTokenTransferFeeConfigUpdates:test_OnlyCallableByOwnerOrAdmin_Revert() (gas: 12327) FeeQuoter_constructor:test_InvalidLinkTokenEqZeroAddress_Revert() (gas: 106573) FeeQuoter_constructor:test_InvalidMaxFeeJuelsPerMsg_Revert() (gas: 110923) FeeQuoter_constructor:test_InvalidStalenessThreshold_Revert() (gas: 110998) FeeQuoter_constructor:test_Setup_Success() (gas: 4974931) -FeeQuoter_convertTokenAmount:test_ConvertTokenAmount_Success() (gas: 68394) +FeeQuoter_convertTokenAmount:test_ConvertTokenAmount_Success() (gas: 68416) FeeQuoter_convertTokenAmount:test_LinkTokenNotSupported_Revert() (gas: 29300) FeeQuoter_getDataAvailabilityCost:test_EmptyMessageCalculatesDataAvailabilityCost_Success() (gas: 96323) -FeeQuoter_getDataAvailabilityCost:test_SimpleMessageCalculatesDataAvailabilityCostUnsupportedDestChainSelector_Success() (gas: 14857) -FeeQuoter_getDataAvailabilityCost:test_SimpleMessageCalculatesDataAvailabilityCost_Success() (gas: 20877) +FeeQuoter_getDataAvailabilityCost:test_SimpleMessageCalculatesDataAvailabilityCostUnsupportedDestChainSelector_Success() (gas: 14835) +FeeQuoter_getDataAvailabilityCost:test_SimpleMessageCalculatesDataAvailabilityCost_Success() (gas: 20944) FeeQuoter_getTokenAndGasPrices:test_GetFeeTokenAndGasPrices_Success() (gas: 73071) FeeQuoter_getTokenAndGasPrices:test_StaleGasPrice_Revert() (gas: 26476) FeeQuoter_getTokenAndGasPrices:test_StalenessCheckDisabled_Success() (gas: 112021) @@ -158,20 +158,20 @@ FeeQuoter_getTokenTransferCost:test_LargeTokenTransferChargesMaxFeeAndGas_Succes FeeQuoter_getTokenTransferCost:test_MixedTokenTransferFee_Success() (gas: 96218) FeeQuoter_getTokenTransferCost:test_NoTokenTransferChargesZeroFee_Success() (gas: 20702) FeeQuoter_getTokenTransferCost:test_SmallTokenTransferChargesMinFeeAndGas_Success() (gas: 28049) -FeeQuoter_getTokenTransferCost:test_ZeroAmountTokenTransferChargesMinFeeAndGas_Success() (gas: 28072) +FeeQuoter_getTokenTransferCost:test_ZeroAmountTokenTransferChargesMinFeeAndGas_Success() (gas: 28094) FeeQuoter_getTokenTransferCost:test_ZeroFeeConfigChargesMinFee_Success() (gas: 40887) FeeQuoter_getTokenTransferCost:test_getTokenTransferCost_selfServeUsesDefaults_Success() (gas: 29801) FeeQuoter_getValidatedFee:test_DestinationChainNotEnabled_Revert() (gas: 18465) FeeQuoter_getValidatedFee:test_EmptyMessage_Success() (gas: 83208) FeeQuoter_getValidatedFee:test_EnforceOutOfOrder_Revert() (gas: 53548) FeeQuoter_getValidatedFee:test_HighGasMessage_Success() (gas: 239604) -FeeQuoter_getValidatedFee:test_InvalidEVMAddress_Revert() (gas: 22646) +FeeQuoter_getValidatedFee:test_InvalidEVMAddress_Revert() (gas: 22668) FeeQuoter_getValidatedFee:test_MessageGasLimitTooHigh_Revert() (gas: 29966) FeeQuoter_getValidatedFee:test_MessageTooLarge_Revert() (gas: 100417) -FeeQuoter_getValidatedFee:test_MessageWithDataAndTokenTransfer_Success() (gas: 143157) +FeeQuoter_getValidatedFee:test_MessageWithDataAndTokenTransfer_Success() (gas: 143112) FeeQuoter_getValidatedFee:test_NotAFeeToken_Revert() (gas: 21280) -FeeQuoter_getValidatedFee:test_SingleTokenMessage_Success() (gas: 114442) -FeeQuoter_getValidatedFee:test_TooManyTokens_Revert() (gas: 23473) +FeeQuoter_getValidatedFee:test_SingleTokenMessage_Success() (gas: 114464) +FeeQuoter_getValidatedFee:test_TooManyTokens_Revert() (gas: 23495) FeeQuoter_getValidatedFee:test_ZeroDataAvailabilityMultiplier_Success() (gas: 63843) FeeQuoter_getValidatedTokenPrice:test_GetValidatedTokenPriceFromFeedErc20Above18Decimals_Success() (gas: 1960306) FeeQuoter_getValidatedTokenPrice:test_GetValidatedTokenPriceFromFeedErc20Below18Decimals_Success() (gas: 1960264) @@ -237,10 +237,10 @@ HybridLockReleaseUSDCTokenPool_releaseOrMint:test_OnLockReleaseMechanism_Success HybridLockReleaseUSDCTokenPool_releaseOrMint:test_WhileMigrationPause_Revert() (gas: 113472) HybridLockReleaseUSDCTokenPool_releaseOrMint:test_incomingMessageWithPrimaryMechanism() (gas: 268981) LockReleaseTokenPool_canAcceptLiquidity:test_CanAcceptLiquidity_Success() (gas: 2788658) -LockReleaseTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Revert() (gas: 30110) +LockReleaseTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Revert() (gas: 30088) LockReleaseTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Success() (gas: 80282) LockReleaseTokenPool_lockOrBurn:test_PoolBurnRevertNotHealthy_Revert() (gas: 59690) -LockReleaseTokenPool_provideLiquidity:test_LiquidityNotAccepted_Revert() (gas: 2785075) +LockReleaseTokenPool_provideLiquidity:test_LiquidityNotAccepted_Revert() (gas: 2785053) LockReleaseTokenPool_provideLiquidity:test_Unauthorized_Revert() (gas: 11489) LockReleaseTokenPool_releaseOrMint:test_ChainNotAllowed_Revert() (gas: 72956) LockReleaseTokenPool_releaseOrMint:test_PoolMintNotHealthy_Revert() (gas: 56476) @@ -250,13 +250,13 @@ LockReleaseTokenPool_setRebalancer:test_SetRebalancer_Success() (gas: 18160) LockReleaseTokenPool_supportsInterface:test_SupportsInterface_Success() (gas: 10250) LockReleaseTokenPool_transferLiquidity:test_transferLiquidity_Success() (gas: 83267) LockReleaseTokenPool_transferLiquidity:test_transferLiquidity_transferTooMuch_Revert() (gas: 56013) -LockReleaseTokenPool_withdrawalLiquidity:test_InsufficientLiquidity_Revert() (gas: 60164) -LockReleaseTokenPool_withdrawalLiquidity:test_Unauthorized_Revert() (gas: 11464) -MerkleMultiProofTest:test_CVE_2023_34459() (gas: 5500) -MerkleMultiProofTest:test_EmptyLeaf_Revert() (gas: 3607) +LockReleaseTokenPool_withdrawalLiquidity:test_InsufficientLiquidity_Revert() (gas: 60182) +LockReleaseTokenPool_withdrawalLiquidity:test_Unauthorized_Revert() (gas: 11486) +MerkleMultiProofTest:test_CVE_2023_34459() (gas: 5456) +MerkleMultiProofTest:test_EmptyLeaf_Revert() (gas: 3563) MerkleMultiProofTest:test_MerkleRoot256() (gas: 394891) MerkleMultiProofTest:test_MerkleRootSingleLeaf_Success() (gas: 3661) -MerkleMultiProofTest:test_SpecSync_gas() (gas: 34107) +MerkleMultiProofTest:test_SpecSync_gas() (gas: 34152) MockRouterTest:test_ccipSendWithInsufficientNativeTokens_Revert() (gas: 34081) MockRouterTest:test_ccipSendWithInvalidMsgValue_Revert() (gas: 60886) MockRouterTest:test_ccipSendWithLinkFeeTokenAndValidMsgValue_Success() (gas: 126575) @@ -313,7 +313,7 @@ MultiAggregateRateLimiter_updateRateLimitTokens:test_ZeroDestToken_AbiEncoded_Re MultiAggregateRateLimiter_updateRateLimitTokens:test_ZeroDestToken_Revert() (gas: 18365) MultiAggregateRateLimiter_updateRateLimitTokens:test_ZeroSourceToken_Revert() (gas: 18294) MultiOCR3Base_setOCR3Configs:test_FMustBePositive_Revert() (gas: 59441) -MultiOCR3Base_setOCR3Configs:test_FTooHigh_Revert() (gas: 44212) +MultiOCR3Base_setOCR3Configs:test_FTooHigh_Revert() (gas: 44190) MultiOCR3Base_setOCR3Configs:test_MoreTransmittersThanSigners_Revert() (gas: 104844) MultiOCR3Base_setOCR3Configs:test_NoTransmitters_Revert() (gas: 18908) MultiOCR3Base_setOCR3Configs:test_RepeatSignerAddress_Revert() (gas: 283842) @@ -330,13 +330,13 @@ MultiOCR3Base_setOCR3Configs:test_TooManySigners_Revert() (gas: 158911) MultiOCR3Base_setOCR3Configs:test_TooManyTransmitters_Revert() (gas: 112357) MultiOCR3Base_setOCR3Configs:test_TransmitterCannotBeZeroAddress_Revert() (gas: 254293) MultiOCR3Base_setOCR3Configs:test_UpdateConfigSigners_Success() (gas: 861787) -MultiOCR3Base_setOCR3Configs:test_UpdateConfigTransmittersWithoutSigners_Success() (gas: 476204) +MultiOCR3Base_setOCR3Configs:test_UpdateConfigTransmittersWithoutSigners_Success() (gas: 476186) MultiOCR3Base_transmit:test_ConfigDigestMismatch_Revert() (gas: 42957) MultiOCR3Base_transmit:test_ForkedChain_Revert() (gas: 48640) MultiOCR3Base_transmit:test_InsufficientSignatures_Revert() (gas: 77185) MultiOCR3Base_transmit:test_NonUniqueSignature_Revert() (gas: 65925) MultiOCR3Base_transmit:test_SignatureOutOfRegistration_Revert() (gas: 33494) -MultiOCR3Base_transmit:test_TooManySignatures_Revert() (gas: 79844) +MultiOCR3Base_transmit:test_TooManySignatures_Revert() (gas: 79889) MultiOCR3Base_transmit:test_TransmitSigners_gas_Success() (gas: 33686) MultiOCR3Base_transmit:test_TransmitWithExtraCalldataArgs_Revert() (gas: 47188) MultiOCR3Base_transmit:test_TransmitWithLessCalldataArgs_Revert() (gas: 25711) @@ -368,16 +368,16 @@ NonceManager_applyPreviousRampsUpdates:test_SingleRampUpdate_success() (gas: 668 NonceManager_applyPreviousRampsUpdates:test_ZeroInput_success() (gas: 12213) NonceManager_typeAndVersion:test_typeAndVersion() (gas: 9705) OffRamp_afterOC3ConfigSet:test_afterOCR3ConfigSet_SignatureVerificationDisabled_Revert() (gas: 5880050) -OffRamp_applySourceChainConfigUpdates:test_AddMultipleChains_Success() (gas: 626115) -OffRamp_applySourceChainConfigUpdates:test_AddNewChain_Success() (gas: 166493) -OffRamp_applySourceChainConfigUpdates:test_ApplyZeroUpdates_Success() (gas: 16741) -OffRamp_applySourceChainConfigUpdates:test_InvalidOnRampUpdate_Revert() (gas: 274735) +OffRamp_applySourceChainConfigUpdates:test_AddMultipleChains_Success() (gas: 626160) +OffRamp_applySourceChainConfigUpdates:test_AddNewChain_Success() (gas: 166527) +OffRamp_applySourceChainConfigUpdates:test_ApplyZeroUpdates_Success() (gas: 16719) +OffRamp_applySourceChainConfigUpdates:test_InvalidOnRampUpdate_Revert() (gas: 274713) OffRamp_applySourceChainConfigUpdates:test_ReplaceExistingChainOnRamp_Success() (gas: 168604) OffRamp_applySourceChainConfigUpdates:test_ReplaceExistingChain_Success() (gas: 181059) -OffRamp_applySourceChainConfigUpdates:test_RouterAddress_Revert() (gas: 13463) -OffRamp_applySourceChainConfigUpdates:test_ZeroOnRampAddress_Revert() (gas: 72746) -OffRamp_applySourceChainConfigUpdates:test_ZeroSourceChainSelector_Revert() (gas: 15476) -OffRamp_applySourceChainConfigUpdates:test_allowNonOnRampUpdateAfterLaneIsUsed_success() (gas: 285063) +OffRamp_applySourceChainConfigUpdates:test_RouterAddress_Revert() (gas: 13441) +OffRamp_applySourceChainConfigUpdates:test_ZeroOnRampAddress_Revert() (gas: 72724) +OffRamp_applySourceChainConfigUpdates:test_ZeroSourceChainSelector_Revert() (gas: 15519) +OffRamp_applySourceChainConfigUpdates:test_allowNonOnRampUpdateAfterLaneIsUsed_success() (gas: 285041) OffRamp_batchExecute:test_MultipleReportsDifferentChainsSkipCursedChain_Success() (gas: 177349) OffRamp_batchExecute:test_MultipleReportsDifferentChains_Success() (gas: 333175) OffRamp_batchExecute:test_MultipleReportsSameChain_Success() (gas: 276441) @@ -386,7 +386,6 @@ OffRamp_batchExecute:test_OutOfBoundsGasLimitsAccess_Revert() (gas: 187853) OffRamp_batchExecute:test_SingleReport_Success() (gas: 156369) OffRamp_batchExecute:test_Unhealthy_Success() (gas: 553439) OffRamp_batchExecute:test_ZeroReports_Revert() (gas: 10600) -OffRamp_ccipReceive:test_RevertWhen_Always() (gas: 9303) OffRamp_commit:test_CommitOnRampMismatch_Revert() (gas: 92744) OffRamp_commit:test_FailedRMNVerification_Reverts() (gas: 63432) OffRamp_commit:test_InvalidIntervalMinLargerThanMax_Revert() (gas: 69993) @@ -436,33 +435,33 @@ OffRamp_executeSingleMessage:test_executeSingleMessage_WithFailingValidationNoRo OffRamp_executeSingleMessage:test_executeSingleMessage_WithFailingValidation_Revert() (gas: 85495) OffRamp_executeSingleMessage:test_executeSingleMessage_WithTokens_Success() (gas: 274279) OffRamp_executeSingleMessage:test_executeSingleMessage_WithVInterception_Success() (gas: 91918) -OffRamp_executeSingleReport:test_DisabledSourceChain_Revert() (gas: 28636) -OffRamp_executeSingleReport:test_EmptyReport_Revert() (gas: 15580) -OffRamp_executeSingleReport:test_InvalidSourcePoolAddress_Success() (gas: 481411) -OffRamp_executeSingleReport:test_ManualExecutionNotYetEnabled_Revert() (gas: 48295) -OffRamp_executeSingleReport:test_MismatchingDestChainSelector_Revert() (gas: 34188) -OffRamp_executeSingleReport:test_NonExistingSourceChain_Revert() (gas: 28823) -OffRamp_executeSingleReport:test_ReceiverError_Success() (gas: 187522) -OffRamp_executeSingleReport:test_RetryFailedMessageWithoutManualExecution_Revert() (gas: 197799) -OffRamp_executeSingleReport:test_RootNotCommitted_Revert() (gas: 40664) -OffRamp_executeSingleReport:test_RouterYULCall_Revert() (gas: 404911) -OffRamp_executeSingleReport:test_SingleMessageNoTokensOtherChain_Success() (gas: 248582) -OffRamp_executeSingleReport:test_SingleMessageNoTokensUnordered_Success() (gas: 192204) -OffRamp_executeSingleReport:test_SingleMessageNoTokens_Success() (gas: 212228) -OffRamp_executeSingleReport:test_SingleMessageToNonCCIPReceiver_Success() (gas: 243641) -OffRamp_executeSingleReport:test_SingleMessagesNoTokensSuccess_gas() (gas: 141397) -OffRamp_executeSingleReport:test_SkippedIncorrectNonceStillExecutes_Success() (gas: 408631) -OffRamp_executeSingleReport:test_SkippedIncorrectNonce_Success() (gas: 58241) -OffRamp_executeSingleReport:test_TokenDataMismatch_Revert() (gas: 73786) -OffRamp_executeSingleReport:test_TwoMessagesWithTokensAndGE_Success() (gas: 582446) -OffRamp_executeSingleReport:test_TwoMessagesWithTokensSuccess_gas() (gas: 531112) -OffRamp_executeSingleReport:test_UnexpectedTokenData_Revert() (gas: 26751) -OffRamp_executeSingleReport:test_UnhealthySingleChainCurse_Revert() (gas: 549057) -OffRamp_executeSingleReport:test_Unhealthy_Success() (gas: 549093) -OffRamp_executeSingleReport:test_WithCurseOnAnotherSourceChain_Success() (gas: 460204) -OffRamp_executeSingleReport:test__execute_SkippedAlreadyExecutedMessageUnordered_Success() (gas: 135139) -OffRamp_executeSingleReport:test__execute_SkippedAlreadyExecutedMessage_Success() (gas: 164782) -OffRamp_getExecutionState:test_FillExecutionState_Success() (gas: 3888824) +OffRamp_executeSingleReport:test_DisabledSourceChain_Revert() (gas: 28666) +OffRamp_executeSingleReport:test_EmptyReport_Revert() (gas: 15584) +OffRamp_executeSingleReport:test_InvalidSourcePoolAddress_Success() (gas: 481487) +OffRamp_executeSingleReport:test_ManualExecutionNotYetEnabled_Revert() (gas: 48303) +OffRamp_executeSingleReport:test_MismatchingDestChainSelector_Revert() (gas: 34108) +OffRamp_executeSingleReport:test_NonExistingSourceChain_Revert() (gas: 28831) +OffRamp_executeSingleReport:test_ReceiverError_Success() (gas: 187607) +OffRamp_executeSingleReport:test_RetryFailedMessageWithoutManualExecution_Revert() (gas: 197746) +OffRamp_executeSingleReport:test_RootNotCommitted_Revert() (gas: 40694) +OffRamp_executeSingleReport:test_RouterYULCall_Revert() (gas: 404953) +OffRamp_executeSingleReport:test_SingleMessageNoTokensOtherChain_Success() (gas: 248622) +OffRamp_executeSingleReport:test_SingleMessageNoTokensUnordered_Success() (gas: 192288) +OffRamp_executeSingleReport:test_SingleMessageNoTokens_Success() (gas: 212314) +OffRamp_executeSingleReport:test_SingleMessageToNonCCIPReceiver_Success() (gas: 243661) +OffRamp_executeSingleReport:test_SingleMessagesNoTokensSuccess_gas() (gas: 141439) +OffRamp_executeSingleReport:test_SkippedIncorrectNonceStillExecutes_Success() (gas: 408713) +OffRamp_executeSingleReport:test_SkippedIncorrectNonce_Success() (gas: 58249) +OffRamp_executeSingleReport:test_TokenDataMismatch_Revert() (gas: 73816) +OffRamp_executeSingleReport:test_TwoMessagesWithTokensAndGE_Success() (gas: 582570) +OffRamp_executeSingleReport:test_TwoMessagesWithTokensSuccess_gas() (gas: 531121) +OffRamp_executeSingleReport:test_UnexpectedTokenData_Revert() (gas: 26755) +OffRamp_executeSingleReport:test_UnhealthySingleChainCurse_Revert() (gas: 549145) +OffRamp_executeSingleReport:test_Unhealthy_Success() (gas: 549092) +OffRamp_executeSingleReport:test_WithCurseOnAnotherSourceChain_Success() (gas: 460234) +OffRamp_executeSingleReport:test__execute_SkippedAlreadyExecutedMessageUnordered_Success() (gas: 135167) +OffRamp_executeSingleReport:test__execute_SkippedAlreadyExecutedMessage_Success() (gas: 164806) +OffRamp_getExecutionState:test_FillExecutionState_Success() (gas: 3888846) OffRamp_getExecutionState:test_GetDifferentChainExecutionState_Success() (gas: 121048) OffRamp_getExecutionState:test_GetExecutionState_Success() (gas: 89561) OffRamp_manuallyExecute:test_ManualExecGasLimitMismatchSingleReport_Revert() (gas: 81178) @@ -488,7 +487,7 @@ OffRamp_releaseOrMintSingleToken:test_releaseOrMintToken_InvalidDataLength_Rever OffRamp_releaseOrMintSingleToken:test_releaseOrMintToken_ReleaseOrMintBalanceMismatch_Revert() (gas: 94670) OffRamp_releaseOrMintSingleToken:test_releaseOrMintToken_TokenHandlingError_BalanceOf_Revert() (gas: 37323) OffRamp_releaseOrMintSingleToken:test_releaseOrMintToken_skip_ReleaseOrMintBalanceMismatch_if_pool_Revert() (gas: 86760) -OffRamp_releaseOrMintTokens:test_TokenHandlingError_Reverts() (gas: 162911) +OffRamp_releaseOrMintTokens:test_TokenHandlingError_Reverts() (gas: 162933) OffRamp_releaseOrMintTokens:test__releaseOrMintTokens_PoolIsNotAPool_Reverts() (gas: 23836) OffRamp_releaseOrMintTokens:test_releaseOrMintTokens_InvalidDataLengthReturnData_Revert() (gas: 62844) OffRamp_releaseOrMintTokens:test_releaseOrMintTokens_PoolDoesNotSupportDest_Reverts() (gas: 80014) @@ -515,28 +514,28 @@ OnRamp_constructor:test_Constructor_InvalidConfigNonceManagerEqAddressZero_Rever OnRamp_constructor:test_Constructor_InvalidConfigRMNProxyEqAddressZero_Revert() (gas: 98066) OnRamp_constructor:test_Constructor_InvalidConfigTokenAdminRegistryEqAddressZero_Revert() (gas: 93146) OnRamp_constructor:test_Constructor_Success() (gas: 2647459) -OnRamp_forwardFromRouter:test_ForwardFromRouterExtraArgsV2AllowOutOfOrderTrue_Success() (gas: 115398) +OnRamp_forwardFromRouter:test_ForwardFromRouterExtraArgsV2AllowOutOfOrderTrue_Success() (gas: 115376) OnRamp_forwardFromRouter:test_ForwardFromRouterExtraArgsV2_Success() (gas: 146244) -OnRamp_forwardFromRouter:test_ForwardFromRouterSuccessCustomExtraArgs() (gas: 145841) -OnRamp_forwardFromRouter:test_ForwardFromRouterSuccessEmptyExtraArgs() (gas: 143957) -OnRamp_forwardFromRouter:test_ForwardFromRouterSuccessLegacyExtraArgs() (gas: 146038) -OnRamp_forwardFromRouter:test_ForwardFromRouter_Success() (gas: 145436) +OnRamp_forwardFromRouter:test_ForwardFromRouterSuccessCustomExtraArgs() (gas: 145819) +OnRamp_forwardFromRouter:test_ForwardFromRouterSuccessEmptyExtraArgs() (gas: 144024) +OnRamp_forwardFromRouter:test_ForwardFromRouterSuccessLegacyExtraArgs() (gas: 146016) +OnRamp_forwardFromRouter:test_ForwardFromRouter_Success() (gas: 145414) OnRamp_forwardFromRouter:test_ForwardFromRouter_Success_ConfigurableSourceRouter() (gas: 140697) OnRamp_forwardFromRouter:test_InvalidExtraArgsTag_Revert() (gas: 38504) -OnRamp_forwardFromRouter:test_MessageInterceptionError_Revert() (gas: 143122) -OnRamp_forwardFromRouter:test_MesssageFeeTooHigh_Revert() (gas: 36611) +OnRamp_forwardFromRouter:test_MessageInterceptionError_Revert() (gas: 143100) +OnRamp_forwardFromRouter:test_MesssageFeeTooHigh_Revert() (gas: 36589) OnRamp_forwardFromRouter:test_MultiCannotSendZeroTokens_Revert() (gas: 36493) OnRamp_forwardFromRouter:test_OriginalSender_Revert() (gas: 18290) -OnRamp_forwardFromRouter:test_Paused_Revert() (gas: 38434) -OnRamp_forwardFromRouter:test_Permissions_Revert() (gas: 23651) -OnRamp_forwardFromRouter:test_ShouldIncrementNonceOnlyOnOrdered_Success() (gas: 186649) -OnRamp_forwardFromRouter:test_ShouldIncrementSeqNumAndNonce_Success() (gas: 213078) -OnRamp_forwardFromRouter:test_ShouldStoreLinkFees() (gas: 147025) -OnRamp_forwardFromRouter:test_ShouldStoreNonLinkFees() (gas: 161214) +OnRamp_forwardFromRouter:test_Paused_Revert() (gas: 38412) +OnRamp_forwardFromRouter:test_Permissions_Revert() (gas: 23629) +OnRamp_forwardFromRouter:test_ShouldIncrementNonceOnlyOnOrdered_Success() (gas: 186583) +OnRamp_forwardFromRouter:test_ShouldIncrementSeqNumAndNonce_Success() (gas: 213012) +OnRamp_forwardFromRouter:test_ShouldStoreLinkFees() (gas: 146992) +OnRamp_forwardFromRouter:test_ShouldStoreNonLinkFees() (gas: 161181) OnRamp_forwardFromRouter:test_SourceTokenDataTooLarge_Revert() (gas: 3576260) OnRamp_forwardFromRouter:test_UnAllowedOriginalSender_Revert() (gas: 24015) -OnRamp_forwardFromRouter:test_UnsupportedToken_Revert() (gas: 75854) -OnRamp_forwardFromRouter:test_forwardFromRouter_UnsupportedToken_Revert() (gas: 38610) +OnRamp_forwardFromRouter:test_UnsupportedToken_Revert() (gas: 75832) +OnRamp_forwardFromRouter:test_forwardFromRouter_UnsupportedToken_Revert() (gas: 38588) OnRamp_forwardFromRouter:test_forwardFromRouter_WithInterception_Success() (gas: 280344) OnRamp_getFee:test_EmptyMessage_Success() (gas: 98692) OnRamp_getFee:test_EnforceOutOfOrder_Revert() (gas: 65453) @@ -623,8 +622,8 @@ RegistryModuleOwnerCustom_registerAdminViaGetCCIPAdmin:test_registerAdminViaGetC RegistryModuleOwnerCustom_registerAdminViaOwner:test_registerAdminViaOwner_Revert() (gas: 19602) RegistryModuleOwnerCustom_registerAdminViaOwner:test_registerAdminViaOwner_Success() (gas: 129930) Router_applyRampUpdates:test_OffRampMismatch_Revert() (gas: 89591) -Router_applyRampUpdates:test_OffRampUpdatesWithRouting() (gas: 10749462) -Router_applyRampUpdates:test_OnRampDisable() (gas: 56428) +Router_applyRampUpdates:test_OffRampUpdatesWithRouting() (gas: 10750087) +Router_applyRampUpdates:test_OnRampDisable() (gas: 56445) Router_applyRampUpdates:test_OnlyOwner_Revert() (gas: 12414) Router_ccipSend:test_CCIPSendLinkFeeNoTokenSuccess_gas() (gas: 131413) Router_ccipSend:test_CCIPSendLinkFeeOneTokenSuccess_gas() (gas: 221240) @@ -655,7 +654,7 @@ Router_routeMessage:test_routeMessage_ExecutionEvent_Success() (gas: 159418) Router_routeMessage:test_routeMessage_ManualExec_Success() (gas: 35723) Router_routeMessage:test_routeMessage_OnlyOffRamp_Revert() (gas: 25376) Router_routeMessage:test_routeMessage_WhenNotHealthy_Revert() (gas: 44812) -Router_setWrappedNative:test_OnlyOwner_Revert() (gas: 11008) +Router_setWrappedNative:test_OnlyOwner_Revert() (gas: 11030) TokenAdminRegistry_acceptAdminRole:test_acceptAdminRole_OnlyPendingAdministrator_Revert() (gas: 51433) TokenAdminRegistry_acceptAdminRole:test_acceptAdminRole_Success() (gas: 44189) TokenAdminRegistry_addRegistryModule:test_addRegistryModule_OnlyOwner_Revert() (gas: 12662) @@ -666,10 +665,10 @@ TokenAdminRegistry_getPools:test_getPools_Success() (gas: 40331) TokenAdminRegistry_isAdministrator:test_isAdministrator_Success() (gas: 106315) TokenAdminRegistry_proposeAdministrator:test_proposeAdministrator_AlreadyRegistered_Revert() (gas: 104412) TokenAdminRegistry_proposeAdministrator:test_proposeAdministrator_OnlyRegistryModule_Revert() (gas: 15643) -TokenAdminRegistry_proposeAdministrator:test_proposeAdministrator_ZeroAddress_Revert() (gas: 15155) +TokenAdminRegistry_proposeAdministrator:test_proposeAdministrator_ZeroAddress_Revert() (gas: 15177) TokenAdminRegistry_proposeAdministrator:test_proposeAdministrator_module_Success() (gas: 113094) TokenAdminRegistry_proposeAdministrator:test_proposeAdministrator_owner_Success() (gas: 108031) -TokenAdminRegistry_proposeAdministrator:test_proposeAdministrator_reRegisterWhileUnclaimed_Success() (gas: 116194) +TokenAdminRegistry_proposeAdministrator:test_proposeAdministrator_reRegisterWhileUnclaimed_Success() (gas: 116216) TokenAdminRegistry_removeRegistryModule:test_removeRegistryModule_OnlyOwner_Revert() (gas: 12651) TokenAdminRegistry_removeRegistryModule:test_removeRegistryModule_Success() (gas: 54735) TokenAdminRegistry_setPool:test_setPool_InvalidTokenPoolToken_Revert() (gas: 19316) @@ -707,7 +706,7 @@ TokenPool_onlyOffRamp:test_onlyOffRamp_Success() (gas: 350358) TokenPool_onlyOnRamp:test_CallerIsNotARampOnRouter_Revert() (gas: 277250) TokenPool_onlyOnRamp:test_ChainNotAllowed_Revert() (gas: 254443) TokenPool_onlyOnRamp:test_onlyOnRamp_Success() (gas: 305359) -TokenPool_setChainRateLimiterConfig:test_NonExistentChain_Revert() (gas: 17225) +TokenPool_setChainRateLimiterConfig:test_NonExistentChain_Revert() (gas: 17203) TokenPool_setChainRateLimiterConfig:test_OnlyOwnerOrRateLimitAdmin_Revert() (gas: 15330) TokenPool_setRateLimitAdmin:test_SetRateLimitAdmin_Revert() (gas: 11024) TokenPool_setRateLimitAdmin:test_SetRateLimitAdmin_Success() (gas: 37584) @@ -746,12 +745,12 @@ USDCBridgeMigrator_updateChainSelectorMechanism:test_lockOrBurn_then_BurnInCCTPM USDCBridgeMigrator_updateChainSelectorMechanism:test_onLockReleaseMechanism_Success() (gas: 147037) USDCBridgeMigrator_updateChainSelectorMechanism:test_onLockReleaseMechanism_thenswitchToPrimary_Success() (gas: 209263) USDCTokenPool__validateMessage:test_ValidateInvalidMessage_Revert() (gas: 25854) -USDCTokenPool_lockOrBurn:test_CallerIsNotARampOnRouter_Revert() (gas: 35504) -USDCTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Revert() (gas: 30235) -USDCTokenPool_lockOrBurn:test_LockOrBurn_Success() (gas: 133470) +USDCTokenPool_lockOrBurn:test_CallerIsNotARampOnRouter_Revert() (gas: 35526) +USDCTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Revert() (gas: 30257) +USDCTokenPool_lockOrBurn:test_LockOrBurn_Success() (gas: 133488) USDCTokenPool_lockOrBurn:test_UnknownDomain_Revert() (gas: 478302) USDCTokenPool_releaseOrMint:test_ReleaseOrMintRealTx_Success() (gas: 268748) -USDCTokenPool_releaseOrMint:test_TokenMaxCapacityExceeded_Revert() (gas: 51004) +USDCTokenPool_releaseOrMint:test_TokenMaxCapacityExceeded_Revert() (gas: 51026) USDCTokenPool_releaseOrMint:test_UnlockingUSDCFailed_Revert() (gas: 99033) USDCTokenPool_setDomains:test_InvalidDomain_Revert() (gas: 66437) USDCTokenPool_setDomains:test_OnlyOwner_Revert() (gas: 11314) diff --git a/contracts/gas-snapshots/keystone.gas-snapshot b/contracts/gas-snapshots/keystone.gas-snapshot index d8ba041a5df..5a52ecb96c9 100644 --- a/contracts/gas-snapshots/keystone.gas-snapshot +++ b/contracts/gas-snapshots/keystone.gas-snapshot @@ -1,38 +1,11 @@ CapabilitiesRegistry_AddCapabilitiesTest:test_AddCapability_NoConfigurationContract() (gas: 154800) CapabilitiesRegistry_AddCapabilitiesTest:test_AddCapability_WithConfiguration() (gas: 180392) -CapabilitiesRegistry_AddCapabilitiesTest:test_RevertWhen_CalledByNonAdmin() (gas: 24678) -CapabilitiesRegistry_AddCapabilitiesTest:test_RevertWhen_CapabilityExists() (gas: 145611) -CapabilitiesRegistry_AddCapabilitiesTest:test_RevertWhen_ConfigurationContractDoesNotMatchInterface() (gas: 94542) -CapabilitiesRegistry_AddCapabilitiesTest:test_RevertWhen_ConfigurationContractNotDeployed() (gas: 96348) CapabilitiesRegistry_AddDONTest:test_AddDON() (gas: 373985) -CapabilitiesRegistry_AddDONTest:test_RevertWhen_CalledByNonAdmin() (gas: 19333) -CapabilitiesRegistry_AddDONTest:test_RevertWhen_CapabilityDoesNotExist() (gas: 169812) -CapabilitiesRegistry_AddDONTest:test_RevertWhen_DeprecatedCapabilityAdded() (gas: 239851) -CapabilitiesRegistry_AddDONTest:test_RevertWhen_DuplicateCapabilityAdded() (gas: 250973) -CapabilitiesRegistry_AddDONTest:test_RevertWhen_DuplicateNodeAdded() (gas: 116928) -CapabilitiesRegistry_AddDONTest:test_RevertWhen_FaultToleranceIsZero() (gas: 43396) -CapabilitiesRegistry_AddDONTest:test_RevertWhen_NodeAlreadyBelongsToWorkflowDON() (gas: 344127) -CapabilitiesRegistry_AddDONTest:test_RevertWhen_NodeDoesNotSupportCapability() (gas: 180188) -CapabilitiesRegistry_AddDONTest_WhenMaliciousCapabilityConfigurationConfigured:test_RevertWhen_MaliciousCapabilitiesConfigContractTriesToRemoveCapabilitiesFromDONNodes() (gas: 340769) CapabilitiesRegistry_AddNodeOperatorsTest:test_AddNodeOperators() (gas: 184201) -CapabilitiesRegistry_AddNodeOperatorsTest:test_RevertWhen_CalledByNonAdmin() (gas: 17624) -CapabilitiesRegistry_AddNodeOperatorsTest:test_RevertWhen_NodeOperatorAdminAddressZero() (gas: 18542) CapabilitiesRegistry_AddNodesTest:test_AddsNodeParams() (gas: 380796) CapabilitiesRegistry_AddNodesTest:test_OwnerCanAddNodes() (gas: 380784) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_AddingDuplicateP2PId() (gas: 323602) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_AddingNodeWithInvalidCapability() (gas: 55328) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_AddingNodeWithInvalidNodeOperator() (gas: 25090) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_AddingNodeWithoutCapabilities() (gas: 27844) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_CalledByNonNodeOperatorAdminAndNonOwner() (gas: 25258) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_EncryptionPublicKeyEmpty() (gas: 29852) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_P2PIDEmpty() (gas: 27558) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_SignerAddressEmpty() (gas: 27241) -CapabilitiesRegistry_AddNodesTest:test_RevertWhen_SignerAddressNotUnique() (gas: 332070) CapabilitiesRegistry_DeprecateCapabilitiesTest:test_DeprecatesCapability() (gas: 89796) CapabilitiesRegistry_DeprecateCapabilitiesTest:test_EmitsEvent() (gas: 89924) -CapabilitiesRegistry_DeprecateCapabilitiesTest:test_RevertWhen_CalledByNonAdmin() (gas: 22911) -CapabilitiesRegistry_DeprecateCapabilitiesTest:test_RevertWhen_CapabilityDoesNotExist() (gas: 16188) -CapabilitiesRegistry_DeprecateCapabilitiesTest:test_RevertWhen_CapabilityIsDeprecated() (gas: 91210) CapabilitiesRegistry_GetCapabilitiesTest:test_ReturnsCapabilities() (gas: 135531) CapabilitiesRegistry_GetDONsTest:test_CorrectlyFetchesDONs() (gas: 65490) CapabilitiesRegistry_GetDONsTest:test_DoesNotIncludeRemovedDONs() (gas: 65060) @@ -46,46 +19,17 @@ CapabilitiesRegistry_GetNodesTest:test_CorrectlyFetchesSpecificNodes() (gas: 321 CapabilitiesRegistry_GetNodesTest:test_DoesNotIncludeRemovedNodes() (gas: 79284) CapabilitiesRegistry_GetNodesTest:test_GetNodesByP2PIdsInvalidNode_Revers() (gas: 26249) CapabilitiesRegistry_RemoveDONsTest:test_RemovesDON() (gas: 55026) -CapabilitiesRegistry_RemoveDONsTest:test_RevertWhen_CalledByNonAdmin() (gas: 15647) -CapabilitiesRegistry_RemoveDONsTest:test_RevertWhen_DONDoesNotExist() (gas: 16561) CapabilitiesRegistry_RemoveNodeOperatorsTest:test_RemovesNodeOperator() (gas: 36157) -CapabilitiesRegistry_RemoveNodeOperatorsTest:test_RevertWhen_CalledByNonOwner() (gas: 15816) CapabilitiesRegistry_RemoveNodesTest:test_CanAddNodeWithSameSignerAddressAfterRemoving() (gas: 117736) CapabilitiesRegistry_RemoveNodesTest:test_CanRemoveWhenDONDeleted() (gas: 288163) CapabilitiesRegistry_RemoveNodesTest:test_CanRemoveWhenNodeNoLongerPartOfDON() (gas: 561487) CapabilitiesRegistry_RemoveNodesTest:test_OwnerCanRemoveNodes() (gas: 77404) CapabilitiesRegistry_RemoveNodesTest:test_RemovesNode() (gas: 79239) -CapabilitiesRegistry_RemoveNodesTest:test_RevertWhen_CalledByNonNodeOperatorAdminAndNonOwner() (gas: 25008) -CapabilitiesRegistry_RemoveNodesTest:test_RevertWhen_NodeDoesNotExist() (gas: 18373) -CapabilitiesRegistry_RemoveNodesTest:test_RevertWhen_NodePartOfCapabilitiesDON() (gas: 385467) -CapabilitiesRegistry_RemoveNodesTest:test_RevertWhen_P2PIDEmpty() (gas: 18363) CapabilitiesRegistry_TypeAndVersionTest:test_TypeAndVersion() (gas: 9768) -CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_CalledByNonAdmin() (gas: 19323) -CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_CapabilityDoesNotExist() (gas: 152958) -CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_DONDoesNotExist() (gas: 17749) -CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_DeprecatedCapabilityAdded() (gas: 222997) -CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_DuplicateCapabilityAdded() (gas: 236986) -CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_DuplicateNodeAdded() (gas: 107687) -CapabilitiesRegistry_UpdateDONTest:test_RevertWhen_NodeDoesNotSupportCapability() (gas: 163401) CapabilitiesRegistry_UpdateDONTest:test_UpdatesDON() (gas: 373535) -CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_CalledByNonAdminAndNonOwner() (gas: 20728) -CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_NodeOperatorAdminIsZeroAddress() (gas: 20097) -CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_NodeOperatorDoesNotExist() (gas: 19790) -CapabilitiesRegistry_UpdateNodeOperatorTest:test_RevertWhen_NodeOperatorIdAndParamLengthsMismatch() (gas: 15452) CapabilitiesRegistry_UpdateNodeOperatorTest:test_UpdatesNodeOperator() (gas: 37144) CapabilitiesRegistry_UpdateNodesTest:test_CanUpdateParamsIfNodeSignerAddressNoLongerUsed() (gas: 261420) CapabilitiesRegistry_UpdateNodesTest:test_OwnerCanUpdateNodes() (gas: 164875) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_AddingNodeWithInvalidCapability() (gas: 36026) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_CalledByAnotherNodeOperatorAdmin() (gas: 29326) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_CalledByNonNodeOperatorAdminAndNonOwner() (gas: 29504) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_EncryptionPublicKeyEmpty() (gas: 29746) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_NodeDoesNotExist() (gas: 29326) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_NodeSignerAlreadyAssignedToAnotherNode() (gas: 31452) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_P2PIDEmpty() (gas: 29292) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_RemovingCapabilityRequiredByCapabilityDON() (gas: 471202) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_RemovingCapabilityRequiredByWorkflowDON() (gas: 341548) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_SignerAddressEmpty() (gas: 29184) -CapabilitiesRegistry_UpdateNodesTest:test_RevertWhen_UpdatingNodeWithoutCapabilities() (gas: 27739) CapabilitiesRegistry_UpdateNodesTest:test_UpdatesNodeParams() (gas: 164929) KeystoneForwarder_ReportTest:test_Report_ConfigVersion() (gas: 2006852) KeystoneForwarder_ReportTest:test_Report_FailedDelieryWhenReportReceiverConsumesAllGas() (gas: 1004833) @@ -94,28 +38,8 @@ KeystoneForwarder_ReportTest:test_Report_FailedDeliveryWhenReceiverNotContract() KeystoneForwarder_ReportTest:test_Report_FailedDeliveryWhenReportReceiverConsumesAllGasAndInterfaceCheckUsesMax() (gas: 440303) KeystoneForwarder_ReportTest:test_Report_SuccessfulDelivery() (gas: 362838) KeystoneForwarder_ReportTest:test_Report_SuccessfulRetryWithMoreGas() (gas: 510677) -KeystoneForwarder_ReportTest:test_RevertWhen_AnySignatureIsInvalid() (gas: 86326) -KeystoneForwarder_ReportTest:test_RevertWhen_AnySignerIsInvalid() (gas: 118476) -KeystoneForwarder_ReportTest:test_RevertWhen_AttemptingTransmissionWithInsufficientGas() (gas: 96629) -KeystoneForwarder_ReportTest:test_RevertWhen_ReportHasDuplicateSignatures() (gas: 94538) -KeystoneForwarder_ReportTest:test_RevertWhen_ReportHasIncorrectDON() (gas: 75930) -KeystoneForwarder_ReportTest:test_RevertWhen_ReportHasInexistentConfigVersion() (gas: 76298) -KeystoneForwarder_ReportTest:test_RevertWhen_ReportIsMalformed() (gas: 45563) -KeystoneForwarder_ReportTest:test_RevertWhen_RetryingInvalidContractTransmission() (gas: 144231) -KeystoneForwarder_ReportTest:test_RevertWhen_RetryingSuccessfulTransmission() (gas: 355976) -KeystoneForwarder_ReportTest:test_RevertWhen_TooFewSignatures() (gas: 55270) -KeystoneForwarder_ReportTest:test_RevertWhen_TooManySignatures() (gas: 56050) -KeystoneForwarder_SetConfigTest:test_RevertWhen_ExcessSigners() (gas: 20184) -KeystoneForwarder_SetConfigTest:test_RevertWhen_FaultToleranceIsZero() (gas: 88057) -KeystoneForwarder_SetConfigTest:test_RevertWhen_InsufficientSigners() (gas: 14555) -KeystoneForwarder_SetConfigTest:test_RevertWhen_NotOwner() (gas: 88766) -KeystoneForwarder_SetConfigTest:test_RevertWhen_ProvidingDuplicateSigners() (gas: 114578) -KeystoneForwarder_SetConfigTest:test_RevertWhen_ProvidingZeroAddressSigner() (gas: 114233) KeystoneForwarder_SetConfigTest:test_SetConfig_FirstTime() (gas: 1540687) KeystoneForwarder_SetConfigTest:test_SetConfig_WhenSignersAreRemoved() (gas: 1535361) KeystoneForwarder_TypeAndVersionTest:test_TypeAndVersion() (gas: 9641) -KeystoneRouter_SetConfigTest:test_AddForwarder_RevertWhen_NotOwner() (gas: 10960) -KeystoneRouter_SetConfigTest:test_RemoveForwarder_RevertWhen_NotOwner() (gas: 10950) KeystoneRouter_SetConfigTest:test_RemoveForwarder_Success() (gas: 17603) -KeystoneRouter_SetConfigTest:test_Route_RevertWhen_UnauthorizedForwarder() (gas: 18530) KeystoneRouter_SetConfigTest:test_Route_Success() (gas: 80948) \ No newline at end of file diff --git a/contracts/gas-snapshots/operatorforwarder.gas-snapshot b/contracts/gas-snapshots/operatorforwarder.gas-snapshot index 724b764a19d..3c9bb6fae51 100644 --- a/contracts/gas-snapshots/operatorforwarder.gas-snapshot +++ b/contracts/gas-snapshots/operatorforwarder.gas-snapshot @@ -2,14 +2,10 @@ FactoryTest:test_DeployNewForwarderAndTransferOwnership_Success() (gas: 1059722) FactoryTest:test_DeployNewForwarder_Success() (gas: 1048209) FactoryTest:test_DeployNewOperatorAndForwarder_Success() (gas: 4069305) FactoryTest:test_DeployNewOperator_Success() (gas: 3020509) -ForwarderTest:test_Forward_Success(uint256) (runs: 257, μ: 226966, ~: 227276) -ForwarderTest:test_MultiForward_Success(uint256,uint256) (runs: 257, μ: 258642, ~: 259185) -ForwarderTest:test_OwnerForward_Success() (gas: 30090) +ForwarderTest:test_OwnerForward_Success() (gas: 30112) ForwarderTest:test_SetAuthorizedSenders_Success() (gas: 160524) -ForwarderTest:test_TransferOwnershipWithMessage_Success() (gas: 35141) +ForwarderTest:test_TransferOwnershipWithMessage_Success() (gas: 35159) OperatorTest:test_CancelOracleRequest_Success() (gas: 274465) OperatorTest:test_FulfillOracleRequest_Success() (gas: 330649) -OperatorTest:test_NotAuthorizedSender_Revert() (gas: 246764) -OperatorTest:test_OracleRequest_Success() (gas: 250043) -OperatorTest:test_SendRequestAndCancelRequest_Success(uint96) (runs: 257, μ: 387179, ~: 387183) -OperatorTest:test_SendRequest_Success(uint96) (runs: 257, μ: 303633, ~: 303636) \ No newline at end of file +OperatorTest:test_NotAuthorizedSender_Revert() (gas: 246781) +OperatorTest:test_OracleRequest_Success() (gas: 250043) \ No newline at end of file diff --git a/contracts/gas-snapshots/shared.gas-snapshot b/contracts/gas-snapshots/shared.gas-snapshot index 9aaf863e12a..755a2c6aaa5 100644 --- a/contracts/gas-snapshots/shared.gas-snapshot +++ b/contracts/gas-snapshots/shared.gas-snapshot @@ -39,18 +39,16 @@ CallWithExactGas__callWithExactGas:test_CallWithExactGasSafeReturnDataExactGas() CallWithExactGas__callWithExactGas:test_NoContractReverts() (gas: 11559) CallWithExactGas__callWithExactGas:test_NoGasForCallExactCheckReverts() (gas: 15788) CallWithExactGas__callWithExactGas:test_NotEnoughGasForCallReverts() (gas: 16241) -CallWithExactGas__callWithExactGas:test_callWithExactGasSuccess(bytes,bytes4) (runs: 257, μ: 15744, ~: 15697) -CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractExactGasSuccess() (gas: 20116) -CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractReceiverErrorSuccess() (gas: 66439) -CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractSuccess(bytes,bytes4) (runs: 257, μ: 16254, ~: 16207) +CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractExactGasSuccess() (gas: 20073) +CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_CallWithExactGasEvenIfTargetIsNoContractReceiverErrorSuccess() (gas: 66461) CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_NoContractSuccess() (gas: 12962) CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_NoGasForCallExactCheckReturnFalseSuccess() (gas: 13005) CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract:test_NotEnoughGasForCallReturnsFalseSuccess() (gas: 13317) CallWithExactGas__callWithExactGasSafeReturnData:test_CallWithExactGasSafeReturnDataExactGas() (gas: 20331) CallWithExactGas__callWithExactGasSafeReturnData:test_NoContractReverts() (gas: 13939) CallWithExactGas__callWithExactGasSafeReturnData:test_NoGasForCallExactCheckReverts() (gas: 16139) -CallWithExactGas__callWithExactGasSafeReturnData:test_NotEnoughGasForCallReverts() (gas: 16569) -CallWithExactGas__callWithExactGasSafeReturnData:test_callWithExactGasSafeReturnData_ThrowOOGError_Revert() (gas: 36711) +CallWithExactGas__callWithExactGasSafeReturnData:test_NotEnoughGasForCallReverts() (gas: 16547) +CallWithExactGas__callWithExactGasSafeReturnData:test_callWithExactGasSafeReturnData_ThrowOOGError_Revert() (gas: 36755) EnumerableMapAddresses_at:testAtSuccess() (gas: 95086) EnumerableMapAddresses_at:testBytes32AtSuccess() (gas: 94855) EnumerableMapAddresses_at:testBytesAtSuccess() (gas: 96542) diff --git a/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver/EtherSenderReceiverTest.ccipReceive.t.sol b/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver/EtherSenderReceiverTest.ccipReceive.t.sol index 4df7e23b3d7..6233b9999d2 100644 --- a/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver/EtherSenderReceiverTest.ccipReceive.t.sol +++ b/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver/EtherSenderReceiverTest.ccipReceive.t.sol @@ -12,7 +12,7 @@ contract EtherSenderReceiverTest_ccipReceive is EtherSenderReceiverTestSetup { error InvalidTokenAmounts(uint256 gotAmounts); error InvalidToken(address gotToken, address expectedToken); - function test_Fuzz_ccipReceive( + function testFuzz_ccipReceive( uint256 tokenAmount ) public { // cap to 10 ether because OWNER only has 10 ether. diff --git a/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver/EtherSenderReceiverTest.ccipSend.t.sol b/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver/EtherSenderReceiverTest.ccipSend.t.sol index a64ce7c2120..dea42f36098 100644 --- a/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver/EtherSenderReceiverTest.ccipSend.t.sol +++ b/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver/EtherSenderReceiverTest.ccipSend.t.sol @@ -13,7 +13,7 @@ contract EtherSenderReceiverTest_ccipSend is EtherSenderReceiverTestSetup { uint256 internal constant FEE_WEI = 121212; uint256 internal constant FEE_JUELS = 232323; - function test_Fuzz_ccipSend(uint256 feeFromRouter, uint256 feeSupplied) public { + function testFuzz_ccipSend(uint256 feeFromRouter, uint256 feeSupplied) public { // cap the fuzzer because OWNER only has a million ether. vm.assume(feeSupplied < 1_000_000 ether - AMOUNT); @@ -56,7 +56,7 @@ contract EtherSenderReceiverTest_ccipSend is EtherSenderReceiverTestSetup { } } - function test_Fuzz_ccipSend_feeToken(uint256 feeFromRouter, uint256 feeSupplied) public { + function testFuzz_ccipSend_feeToken(uint256 feeFromRouter, uint256 feeSupplied) public { // cap the fuzzer because OWNER only has a million LINK. vm.assume(feeSupplied < 1_000_000 ether - AMOUNT); diff --git a/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver/EtherSenderReceiverTest.validatedMessage.t.sol b/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver/EtherSenderReceiverTest.validatedMessage.t.sol index 91ccf2034d9..d6ececefd96 100644 --- a/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver/EtherSenderReceiverTest.validatedMessage.t.sol +++ b/contracts/src/v0.8/ccip/test/applications/EtherSenderReceiver/EtherSenderReceiverTest.validatedMessage.t.sol @@ -10,7 +10,7 @@ contract EtherSenderReceiverTest_validatedMessage is EtherSenderReceiverTestSetu error InvalidWethAddress(address want, address got); error GasLimitTooLow(uint256 minLimit, uint256 gotLimit); - function test_Fuzz_validatedMessage_msgSenderOverwrite( + function testFuzz_validatedMessage_msgSenderOverwrite( bytes memory data ) public view { Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1); @@ -35,7 +35,7 @@ contract EtherSenderReceiverTest_validatedMessage is EtherSenderReceiverTestSetu assertEq(validatedMessage.extraArgs, bytes(""), "extraArgs must be empty"); } - function test_Fuzz_validatedMessage_tokenAddressOverwrite( + function testFuzz_validatedMessage_tokenAddressOverwrite( address token ) public view { Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1); diff --git a/contracts/src/v0.8/ccip/test/applications/PingPong/PingPong.setCounterpart.t.sol b/contracts/src/v0.8/ccip/test/applications/PingPong/PingPong.setCounterpart.t.sol index 365ccf33e71..8db2e75c5d7 100644 --- a/contracts/src/v0.8/ccip/test/applications/PingPong/PingPong.setCounterpart.t.sol +++ b/contracts/src/v0.8/ccip/test/applications/PingPong/PingPong.setCounterpart.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.24; import {PingPongDappSetup} from "./PingPongDappSetup.t.sol"; contract PingPong_setCounterpart is PingPongDappSetup { - function test_Fuzz_CounterPartAddress_Success(uint64 chainSelector, address counterpartAddress) public { + function testFuzz_CounterPartAddress_Success(uint64 chainSelector, address counterpartAddress) public { s_pingPong.setCounterpartChainSelector(chainSelector); s_pingPong.setCounterpart(chainSelector, counterpartAddress); diff --git a/contracts/src/v0.8/ccip/test/applications/PingPong/PingPong.setCounterpartAddress.t.sol b/contracts/src/v0.8/ccip/test/applications/PingPong/PingPong.setCounterpartAddress.t.sol index 6762d8aab85..0e5587dac5f 100644 --- a/contracts/src/v0.8/ccip/test/applications/PingPong/PingPong.setCounterpartAddress.t.sol +++ b/contracts/src/v0.8/ccip/test/applications/PingPong/PingPong.setCounterpartAddress.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.24; import {PingPongDappSetup} from "./PingPongDappSetup.t.sol"; contract PingPong_setCounterpartAddress is PingPongDappSetup { - function test_Fuzz_CounterPartAddress_Success( + function testFuzz_CounterPartAddress_Success( address counterpartAddress ) public { s_pingPong.setCounterpartAddress(counterpartAddress); diff --git a/contracts/src/v0.8/ccip/test/applications/PingPong/PingPong.setCounterpartChainSelector.t.sol b/contracts/src/v0.8/ccip/test/applications/PingPong/PingPong.setCounterpartChainSelector.t.sol index a6fea957753..a7d148089bc 100644 --- a/contracts/src/v0.8/ccip/test/applications/PingPong/PingPong.setCounterpartChainSelector.t.sol +++ b/contracts/src/v0.8/ccip/test/applications/PingPong/PingPong.setCounterpartChainSelector.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.24; import {PingPongDappSetup} from "./PingPongDappSetup.t.sol"; contract PingPong_setCounterpartChainSelector is PingPongDappSetup { - function test_Fuzz_CounterPartChainSelector_Success( + function testFuzz_CounterPartChainSelector_Success( uint64 chainSelector ) public { s_pingPong.setCounterpartChainSelector(chainSelector); diff --git a/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.applyDestChainConfigUpdates.t.sol b/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.applyDestChainConfigUpdates.t.sol index 44fe0e33eba..b663151a96c 100644 --- a/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.applyDestChainConfigUpdates.t.sol +++ b/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.applyDestChainConfigUpdates.t.sol @@ -6,7 +6,7 @@ import {Internal} from "../../libraries/Internal.sol"; import {FeeQuoterSetup} from "./FeeQuoterSetup.t.sol"; contract FeeQuoter_applyDestChainConfigUpdates is FeeQuoterSetup { - function test_Fuzz_applyDestChainConfigUpdates_Success( + function testFuzz_applyDestChainConfigUpdates_Success( FeeQuoter.DestChainConfigArgs memory destChainConfigArgs ) public { vm.assume(destChainConfigArgs.destChainSelector != 0); diff --git a/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.applyPremiumMultiplierWeiPerEthUpdates.t.sol b/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.applyPremiumMultiplierWeiPerEthUpdates.t.sol index d31202e8a99..67b1ed9ae92 100644 --- a/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.applyPremiumMultiplierWeiPerEthUpdates.t.sol +++ b/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.applyPremiumMultiplierWeiPerEthUpdates.t.sol @@ -6,7 +6,7 @@ import {FeeQuoter} from "../../FeeQuoter.sol"; import {FeeQuoterSetup} from "./FeeQuoterSetup.t.sol"; contract FeeQuoter_applyPremiumMultiplierWeiPerEthUpdates is FeeQuoterSetup { - function test_Fuzz_applyPremiumMultiplierWeiPerEthUpdates_Success( + function testFuzz_applyPremiumMultiplierWeiPerEthUpdates_Success( FeeQuoter.PremiumMultiplierWeiPerEthArgs memory premiumMultiplierWeiPerEthArg ) public { FeeQuoter.PremiumMultiplierWeiPerEthArgs[] memory premiumMultiplierWeiPerEthArgs = diff --git a/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.applyTokenTransferFeeConfigUpdates.t.sol b/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.applyTokenTransferFeeConfigUpdates.t.sol index 72ef7b89a75..711374a2441 100644 --- a/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.applyTokenTransferFeeConfigUpdates.t.sol +++ b/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.applyTokenTransferFeeConfigUpdates.t.sol @@ -7,7 +7,7 @@ import {Pool} from "../../libraries/Pool.sol"; import {FeeQuoterSetup} from "./FeeQuoterSetup.t.sol"; contract FeeQuoter_applyTokenTransferFeeConfigUpdates is FeeQuoterSetup { - function test_Fuzz_ApplyTokenTransferFeeConfig_Success( + function testFuzz_ApplyTokenTransferFeeConfig_Success( FeeQuoter.TokenTransferFeeConfig[2] memory tokenTransferFeeConfigs ) public { // To prevent Invalid Fee Range error from the fuzzer, bound the results to a valid range that diff --git a/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.convertTokenAmount.t.sol b/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.convertTokenAmount.t.sol index ca6a7e16126..33e941cfbe3 100644 --- a/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.convertTokenAmount.t.sol +++ b/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.convertTokenAmount.t.sol @@ -15,7 +15,7 @@ contract FeeQuoter_convertTokenAmount is FeeQuoterSetup { assertEq(s_feeQuoter.convertTokenAmount(s_weth, amount, s_sourceTokens[0]), expected); } - function test_Fuzz_ConvertTokenAmount_Success( + function testFuzz_ConvertTokenAmount_Success( uint256 feeTokenAmount, uint224 usdPerFeeToken, uint160 usdPerLinkToken, diff --git a/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.getDataAvailabilityCost.t.sol b/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.getDataAvailabilityCost.t.sol index 2e498746c3d..6f2566ac754 100644 --- a/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.getDataAvailabilityCost.t.sol +++ b/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.getDataAvailabilityCost.t.sol @@ -64,7 +64,7 @@ contract FeeQuoter_getDataAvailabilityCost is FeeQuoterSetup { assertEq(dataAvailabilityCostUSD, 0); } - function test_Fuzz_ZeroDataAvailabilityGasPriceAlwaysCalculatesZeroDataAvailabilityCost_Success( + function testFuzz_ZeroDataAvailabilityGasPriceAlwaysCalculatesZeroDataAvailabilityCost_Success( uint64 messageDataLength, uint32 numberOfTokens, uint32 tokenTransferBytesOverhead @@ -76,7 +76,7 @@ contract FeeQuoter_getDataAvailabilityCost is FeeQuoterSetup { assertEq(0, dataAvailabilityCostUSD); } - function test_Fuzz_CalculateDataAvailabilityCost_Success( + function testFuzz_CalculateDataAvailabilityCost_Success( uint64 destChainSelector, uint32 destDataAvailabilityOverheadGas, uint16 destGasPerDataAvailabilityByte, diff --git a/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.getTokenTransferCost.t.sol b/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.getTokenTransferCost.t.sol index a426775ca63..9f0aa9440b8 100644 --- a/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.getTokenTransferCost.t.sol +++ b/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.getTokenTransferCost.t.sol @@ -158,7 +158,7 @@ contract FeeQuoter_getTokenTransferCost is FeeQuoterFeeSetup { assertEq(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES, destBytesOverhead); } - function test_Fuzz_TokenTransferFeeDuplicateTokens_Success(uint256 transfers, uint256 amount) public view { + function testFuzz_TokenTransferFeeDuplicateTokens_Success(uint256 transfers, uint256 amount) public view { // It shouldn't be possible to pay materially lower fees by splitting up the transfers. // Note it is possible to pay higher fees since the minimum fees are added. FeeQuoter.DestChainConfig memory destChainConfig = s_feeQuoter.getDestChainConfig(DEST_CHAIN_SELECTOR); diff --git a/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.getValidatedFee.t.sol b/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.getValidatedFee.t.sol index fdafde91f62..1f76f3120ae 100644 --- a/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.getValidatedFee.t.sol +++ b/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoter.getValidatedFee.t.sol @@ -171,7 +171,7 @@ contract FeeQuoter_getValidatedFee is FeeQuoterFeeSetup { } } - function test_Fuzz_EnforceOutOfOrder(bool enforce, bool allowOutOfOrderExecution) public { + function testFuzz_EnforceOutOfOrder(bool enforce, bool allowOutOfOrderExecution) public { // Update config to enforce allowOutOfOrderExecution = defaultVal. vm.stopPrank(); vm.startPrank(OWNER); diff --git a/contracts/src/v0.8/ccip/test/libraries/MerkleMultiProof.t.sol b/contracts/src/v0.8/ccip/test/libraries/MerkleMultiProof.t.sol index e7a9462c93b..4f03f3e6f55 100644 --- a/contracts/src/v0.8/ccip/test/libraries/MerkleMultiProof.t.sol +++ b/contracts/src/v0.8/ccip/test/libraries/MerkleMultiProof.t.sol @@ -64,7 +64,7 @@ contract MerkleMultiProofTest is Test { assertEq(expectedRoot, root); } - function test_Fuzz_MerkleRoot2(bytes32 left, bytes32 right) public pure { + function testFuzz_MerkleRoot2(bytes32 left, bytes32 right) public pure { bytes32[] memory leaves = new bytes32[](2); leaves[0] = left; leaves[1] = right; @@ -91,7 +91,7 @@ contract MerkleMultiProofTest is Test { assertEq(root, expectedRoot); } - function test_Fuzz_MerkleMulti1of4(bytes32 leaf1, bytes32 proof1, bytes32 proof2) public pure { + function testFuzz_MerkleMulti1of4(bytes32 leaf1, bytes32 proof1, bytes32 proof2) public pure { bytes32[] memory leaves = new bytes32[](1); leaves[0] = leaf1; bytes32[] memory proofs = new bytes32[](2); @@ -106,7 +106,7 @@ contract MerkleMultiProofTest is Test { assertEq(MerkleMultiProof._merkleRoot(leaves, proofs, 0), result); } - function test_Fuzz_MerkleMulti2of4(bytes32 leaf1, bytes32 leaf2, bytes32 proof1, bytes32 proof2) public pure { + function testFuzz_MerkleMulti2of4(bytes32 leaf1, bytes32 leaf2, bytes32 proof1, bytes32 proof2) public pure { bytes32[] memory leaves = new bytes32[](2); leaves[0] = leaf1; leaves[1] = leaf2; @@ -124,7 +124,7 @@ contract MerkleMultiProofTest is Test { assertEq(MerkleMultiProof._merkleRoot(leaves, proofs, 4), finalResult); } - function test_Fuzz_MerkleMulti3of4(bytes32 leaf1, bytes32 leaf2, bytes32 leaf3, bytes32 proof) public pure { + function testFuzz_MerkleMulti3of4(bytes32 leaf1, bytes32 leaf2, bytes32 leaf3, bytes32 proof) public pure { bytes32[] memory leaves = new bytes32[](3); leaves[0] = leaf1; leaves[1] = leaf2; @@ -142,7 +142,7 @@ contract MerkleMultiProofTest is Test { assertEq(MerkleMultiProof._merkleRoot(leaves, proofs, 5), finalResult); } - function test_Fuzz_MerkleMulti4of4(bytes32 leaf1, bytes32 leaf2, bytes32 leaf3, bytes32 leaf4) public pure { + function testFuzz_MerkleMulti4of4(bytes32 leaf1, bytes32 leaf2, bytes32 leaf3, bytes32 leaf4) public pure { bytes32[] memory leaves = new bytes32[](4); leaves[0] = leaf1; leaves[1] = leaf2; diff --git a/contracts/src/v0.8/ccip/test/ocr/MultiOCR3Base/MultiOCR3Base.setOCR3Configs.t.sol b/contracts/src/v0.8/ccip/test/ocr/MultiOCR3Base/MultiOCR3Base.setOCR3Configs.t.sol index 458767a4512..c70a8666654 100644 --- a/contracts/src/v0.8/ccip/test/ocr/MultiOCR3Base/MultiOCR3Base.setOCR3Configs.t.sol +++ b/contracts/src/v0.8/ccip/test/ocr/MultiOCR3Base/MultiOCR3Base.setOCR3Configs.t.sol @@ -256,7 +256,7 @@ contract MultiOCR3Base_setOCR3Configs is MultiOCR3BaseSetup { _assertOCRConfigUnconfigured(s_multiOCR3.latestConfigDetails(3)); } - function test_Fuzz_SetConfig_Success(MultiOCR3Base.OCRConfigArgs memory ocrConfig, uint64 randomAddressOffset) public { + function testFuzz_SetConfig_Success(MultiOCR3Base.OCRConfigArgs memory ocrConfig, uint64 randomAddressOffset) public { // condition: cannot assume max oracle count vm.assume(ocrConfig.transmitters.length <= 255); vm.assume(ocrConfig.signers.length <= 255); diff --git a/contracts/src/v0.8/ccip/test/ocr/MultiOCR3Base/MultiOCR3Base.transmit.t.sol b/contracts/src/v0.8/ccip/test/ocr/MultiOCR3Base/MultiOCR3Base.transmit.t.sol index 3d619dfa116..c6d948a70c2 100644 --- a/contracts/src/v0.8/ccip/test/ocr/MultiOCR3Base/MultiOCR3Base.transmit.t.sol +++ b/contracts/src/v0.8/ccip/test/ocr/MultiOCR3Base/MultiOCR3Base.transmit.t.sol @@ -77,7 +77,7 @@ contract MultiOCR3Base_transmit is MultiOCR3BaseSetup { s_multiOCR3.transmitWithoutSignatures(reportContext, REPORT); } - function test_Fuzz_TransmitSignersWithSignatures_Success(uint8 F, uint64 randomAddressOffset) public { + function testFuzz_TransmitSignersWithSignatures_Success(uint8 F, uint64 randomAddressOffset) public { vm.pauseGasMetering(); F = uint8(bound(F, 1, 3)); diff --git a/contracts/src/v0.8/ccip/test/offRamp/OffRamp/OffRamp.applySourceChainConfigUpdates.t.sol b/contracts/src/v0.8/ccip/test/offRamp/OffRamp/OffRamp.applySourceChainConfigUpdates.t.sol index 7ed5c22b800..84c522108ae 100644 --- a/contracts/src/v0.8/ccip/test/offRamp/OffRamp/OffRamp.applySourceChainConfigUpdates.t.sol +++ b/contracts/src/v0.8/ccip/test/offRamp/OffRamp/OffRamp.applySourceChainConfigUpdates.t.sol @@ -126,7 +126,7 @@ contract OffRamp_applySourceChainConfigUpdates is OffRampSetup { // Setting lower fuzz run as 256 runs was sometimes resulting in flakes. /// forge-config: default.fuzz.runs = 32 /// forge-config: ccip.fuzz.runs = 32 - function test_Fuzz_applySourceChainConfigUpdate_Success( + function testFuzz_applySourceChainConfigUpdate_Success( OffRamp.SourceChainConfigArgs memory sourceChainConfigArgs ) public { // Skip invalid inputs diff --git a/contracts/src/v0.8/ccip/test/offRamp/OffRamp/OffRamp.executeSingleReport.t.sol b/contracts/src/v0.8/ccip/test/offRamp/OffRamp/OffRamp.executeSingleReport.t.sol index e651ad3836a..4894cd2544c 100644 --- a/contracts/src/v0.8/ccip/test/offRamp/OffRamp/OffRamp.executeSingleReport.t.sol +++ b/contracts/src/v0.8/ccip/test/offRamp/OffRamp/OffRamp.executeSingleReport.t.sol @@ -374,7 +374,7 @@ contract OffRamp_executeSingleReport is OffRampSetup { assertEq(uint64(2), s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(OWNER))); } - function test_Fuzz_InterleavingOrderedAndUnorderedMessages_Success( + function testFuzz_InterleavingOrderedAndUnorderedMessages_Success( bool[7] memory orderings ) public { Internal.Any2EVMRampMessage[] memory messages = new Internal.Any2EVMRampMessage[](orderings.length); diff --git a/contracts/src/v0.8/ccip/test/offRamp/OffRamp/OffRamp.getExecutionState.t.sol b/contracts/src/v0.8/ccip/test/offRamp/OffRamp/OffRamp.getExecutionState.t.sol index 9b8e719053b..ac9cfe86cd9 100644 --- a/contracts/src/v0.8/ccip/test/offRamp/OffRamp/OffRamp.getExecutionState.t.sol +++ b/contracts/src/v0.8/ccip/test/offRamp/OffRamp/OffRamp.getExecutionState.t.sol @@ -10,7 +10,7 @@ contract OffRamp_getExecutionState is OffRampSetup { /// forge-config: default.fuzz.runs = 32 /// forge-config: ccip.fuzz.runs = 32 - function test_Fuzz_Differential_Success( + function testFuzz_Differential_Success( uint64 sourceChainSelector, uint16[500] memory seqNums, uint8[500] memory values diff --git a/contracts/src/v0.8/ccip/test/offRamp/OffRamp/OffRamp.releaseOrMintTokens.t.sol b/contracts/src/v0.8/ccip/test/offRamp/OffRamp/OffRamp.releaseOrMintTokens.t.sol index 22f82bdf694..74594f7031d 100644 --- a/contracts/src/v0.8/ccip/test/offRamp/OffRamp/OffRamp.releaseOrMintTokens.t.sol +++ b/contracts/src/v0.8/ccip/test/offRamp/OffRamp/OffRamp.releaseOrMintTokens.t.sol @@ -224,7 +224,7 @@ contract OffRamp_releaseOrMintTokens is OffRampSetup { /// forge-config: default.fuzz.runs = 32 /// forge-config: ccip.fuzz.runs = 1024 // Uint256 gives a good range of values to test, both inside and outside of the eth address space. - function test_Fuzz__releaseOrMintTokens_AnyRevertIsCaught_Success( + function testFuzz__releaseOrMintTokens_AnyRevertIsCaught_Success( address destPool ) public { // Input 447301751254033913445893214690834296930546521452, which is 0x4E59B44847B379578588920CA78FBF26C0B4956C diff --git a/contracts/src/v0.8/ccip/test/onRamp/OnRamp/OnRamp.forwardFromRouter.t.sol b/contracts/src/v0.8/ccip/test/onRamp/OnRamp/OnRamp.forwardFromRouter.t.sol index 076377c34c5..764cd44df22 100644 --- a/contracts/src/v0.8/ccip/test/onRamp/OnRamp/OnRamp.forwardFromRouter.t.sol +++ b/contracts/src/v0.8/ccip/test/onRamp/OnRamp/OnRamp.forwardFromRouter.t.sol @@ -238,7 +238,7 @@ contract OnRamp_forwardFromRouter is OnRampSetup { // https://github.com/foundry-rs/foundry/issues/5689 /// forge-dynamicConfig: default.fuzz.runs = 32 /// forge-dynamicConfig: ccip.fuzz.runs = 32 - function test_Fuzz_ForwardFromRouter_Success(address originalSender, address receiver, uint96 feeTokenAmount) public { + function testFuzz_ForwardFromRouter_Success(address originalSender, address receiver, uint96 feeTokenAmount) public { // To avoid RouterMustSetOriginalSender vm.assume(originalSender != address(0)); vm.assume(uint160(receiver) >= Internal.PRECOMPILE_SPACE); diff --git a/contracts/src/v0.8/ccip/test/onRamp/OnRamp/OnRamp.withdrawFeeTokens.t.sol b/contracts/src/v0.8/ccip/test/onRamp/OnRamp/OnRamp.withdrawFeeTokens.t.sol index d4a297c103c..2af7242150a 100644 --- a/contracts/src/v0.8/ccip/test/onRamp/OnRamp/OnRamp.withdrawFeeTokens.t.sol +++ b/contracts/src/v0.8/ccip/test/onRamp/OnRamp/OnRamp.withdrawFeeTokens.t.sol @@ -31,7 +31,7 @@ contract OnRamp_withdrawFeeTokens is OnRampSetup { } } - function test_Fuzz_WithdrawFeeTokens_Success( + function testFuzz_WithdrawFeeTokens_Success( uint256[5] memory amounts ) public { vm.startPrank(OWNER); diff --git a/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool/LockReleaseTokenPool.lockOrBurn.t.sol b/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool/LockReleaseTokenPool.lockOrBurn.t.sol index 667386ae7e0..7c87fbcc95d 100644 --- a/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool/LockReleaseTokenPool.lockOrBurn.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool/LockReleaseTokenPool.lockOrBurn.t.sol @@ -8,7 +8,7 @@ import {TokenPool} from "../../../pools/TokenPool.sol"; import {LockReleaseTokenPoolSetup} from "./LockReleaseTokenPoolSetup.t.sol"; contract LockReleaseTokenPool_lockOrBurn is LockReleaseTokenPoolSetup { - function test_Fuzz_LockOrBurnNoAllowList_Success( + function testFuzz_LockOrBurnNoAllowList_Success( uint256 amount ) public { amount = bound(amount, 1, _getOutboundRateLimiterConfig().capacity); diff --git a/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool/LockReleaseTokenPool.provideLiquidity.t.sol b/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool/LockReleaseTokenPool.provideLiquidity.t.sol index 664d9526063..f402750eb19 100644 --- a/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool/LockReleaseTokenPool.provideLiquidity.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool/LockReleaseTokenPool.provideLiquidity.t.sol @@ -7,7 +7,7 @@ import {TokenPool} from "../../../pools/TokenPool.sol"; import {LockReleaseTokenPoolSetup} from "./LockReleaseTokenPoolSetup.t.sol"; contract LockReleaseTokenPool_provideLiquidity is LockReleaseTokenPoolSetup { - function test_Fuzz_ProvideLiquidity_Success( + function testFuzz_ProvideLiquidity_Success( uint256 amount ) public { uint256 balancePre = s_token.balanceOf(OWNER); @@ -28,7 +28,7 @@ contract LockReleaseTokenPool_provideLiquidity is LockReleaseTokenPoolSetup { s_lockReleaseTokenPool.provideLiquidity(1); } - function test_Fuzz_ExceedsAllowance( + function testFuzz_ExceedsAllowance( uint256 amount ) public { vm.assume(amount > 0); diff --git a/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool/LockReleaseTokenPool.releaseOrMint.t.sol b/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool/LockReleaseTokenPool.releaseOrMint.t.sol index 06ccfc38065..b20b19fe973 100644 --- a/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool/LockReleaseTokenPool.releaseOrMint.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool/LockReleaseTokenPool.releaseOrMint.t.sol @@ -49,7 +49,7 @@ contract LockReleaseTokenPool_releaseOrMint is LockReleaseTokenPoolSetup { ); } - function test_Fuzz_ReleaseOrMint_Success(address recipient, uint256 amount) public { + function testFuzz_ReleaseOrMint_Success(address recipient, uint256 amount) public { // Since the owner already has tokens this would break the checks vm.assume(recipient != OWNER); vm.assume(recipient != address(0)); diff --git a/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool/LockReleaseTokenPool.withdrawalLiquidity.t.sol b/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool/LockReleaseTokenPool.withdrawalLiquidity.t.sol index 0a2b7b28b0f..29b6ef6c7f8 100644 --- a/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool/LockReleaseTokenPool.withdrawalLiquidity.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/LockReleaseTokenPool/LockReleaseTokenPool.withdrawalLiquidity.t.sol @@ -7,7 +7,7 @@ import {TokenPool} from "../../../pools/TokenPool.sol"; import {LockReleaseTokenPoolSetup} from "./LockReleaseTokenPoolSetup.t.sol"; contract LockReleaseTokenPool_withdrawalLiquidity is LockReleaseTokenPoolSetup { - function test_Fuzz_WithdrawalLiquidity_Success( + function testFuzz_WithdrawalLiquidity_Success( uint256 amount ) public { uint256 balancePre = s_token.balanceOf(OWNER); diff --git a/contracts/src/v0.8/ccip/test/pools/TokenPool/TokenPool.setChainRateLimiterConfig.t.sol b/contracts/src/v0.8/ccip/test/pools/TokenPool/TokenPool.setChainRateLimiterConfig.t.sol index bee2218a7ff..e44dc96f1a8 100644 --- a/contracts/src/v0.8/ccip/test/pools/TokenPool/TokenPool.setChainRateLimiterConfig.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/TokenPool/TokenPool.setChainRateLimiterConfig.t.sol @@ -23,7 +23,7 @@ contract TokenPool_setChainRateLimiterConfig is TokenPoolSetup { s_tokenPool.applyChainUpdates(chainUpdates); } - function test_Fuzz_SetChainRateLimiterConfig_Success(uint128 capacity, uint128 rate, uint32 newTime) public { + function testFuzz_SetChainRateLimiterConfig_Success(uint128 capacity, uint128 rate, uint32 newTime) public { // Cap the lower bound to 4 so 4/2 is still >= 2 vm.assume(capacity >= 4); // Cap the lower bound to 2 so 2/2 is still >= 1 diff --git a/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPool.lockOrBurn.t.sol b/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPool.lockOrBurn.t.sol index 2ca33ad4f5f..9be60c97218 100644 --- a/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPool.lockOrBurn.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPool.lockOrBurn.t.sol @@ -52,7 +52,7 @@ contract USDCTokenPool_lockOrBurn is USDCTokenPoolSetup { assertEq(s_mockUSDC.s_nonce() - 1, nonce); } - function test_Fuzz_LockOrBurn_Success(bytes32 destinationReceiver, uint256 amount) public { + function testFuzz_LockOrBurn_Success(bytes32 destinationReceiver, uint256 amount) public { vm.assume(destinationReceiver != bytes32(0)); amount = bound(amount, 1, _getOutboundRateLimiterConfig().capacity); s_token.transfer(address(s_usdcTokenPool), amount); @@ -93,7 +93,7 @@ contract USDCTokenPool_lockOrBurn is USDCTokenPoolSetup { assertEq(poolReturnDataV1.destTokenAddress, abi.encode(DEST_CHAIN_USDC_TOKEN)); } - function test_Fuzz_LockOrBurnWithAllowList_Success(bytes32 destinationReceiver, uint256 amount) public { + function testFuzz_LockOrBurnWithAllowList_Success(bytes32 destinationReceiver, uint256 amount) public { vm.assume(destinationReceiver != bytes32(0)); amount = bound(amount, 1, _getOutboundRateLimiterConfig().capacity); s_token.transfer(address(s_usdcTokenPoolWithAllowList), amount); diff --git a/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPool.releaseOrMint.t.sol b/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPool.releaseOrMint.t.sol index f4ffde6c82c..4499c748a6b 100644 --- a/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPool.releaseOrMint.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPool.releaseOrMint.t.sol @@ -21,7 +21,7 @@ contract USDCTokenPool_releaseOrMint is USDCTokenPoolSetup { return abi.encodePacked(_version, _burnToken, _mintRecipient, _amount, _messageSender); } - function test_Fuzz_ReleaseOrMint_Success(address recipient, uint256 amount) public { + function testFuzz_ReleaseOrMint_Success(address recipient, uint256 amount) public { vm.assume(recipient != address(0) && recipient != address(s_token)); amount = bound(amount, 0, _getInboundRateLimiterConfig().capacity); diff --git a/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPool.setDomains.t.sol b/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPool.setDomains.t.sol index 1fe5d828bdb..7fcb75fdf3f 100644 --- a/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPool.setDomains.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPool.setDomains.t.sol @@ -11,7 +11,7 @@ contract USDCTokenPool_setDomains is USDCTokenPoolSetup { // Setting lower fuzz run as 256 runs was causing differing gas results in snapshot. /// forge-config: default.fuzz.runs = 32 /// forge-config: ccip.fuzz.runs = 32 - function test_Fuzz_SetDomains_Success( + function testFuzz_SetDomains_Success( bytes32[5] calldata allowedCallers, uint32[5] calldata domainIdentifiers, uint64[5] calldata destChainSelectors diff --git a/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPool.validateMessage.t.sol b/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPool.validateMessage.t.sol index c53fa6e81b9..975368c38b9 100644 --- a/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPool.validateMessage.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPool.validateMessage.t.sol @@ -5,7 +5,7 @@ import {USDCTokenPool} from "../../../../pools/USDC/USDCTokenPool.sol"; import {USDCTokenPoolSetup} from "./USDCTokenPoolSetup.t.sol"; contract USDCTokenPool__validateMessage is USDCTokenPoolSetup { - function test_Fuzz_ValidateMessage_Success(uint32 sourceDomain, uint64 nonce) public { + function testFuzz_ValidateMessage_Success(uint32 sourceDomain, uint64 nonce) public { vm.pauseGasMetering(); USDCMessage memory usdcMessage = USDCMessage({ version: 0, diff --git a/contracts/src/v0.8/ccip/test/router/Router/Router.applyRampUpdates.t.sol b/contracts/src/v0.8/ccip/test/router/Router/Router.applyRampUpdates.t.sol index f877a4c6532..9b46741f96d 100644 --- a/contracts/src/v0.8/ccip/test/router/Router/Router.applyRampUpdates.t.sol +++ b/contracts/src/v0.8/ccip/test/router/Router/Router.applyRampUpdates.t.sol @@ -38,7 +38,7 @@ contract Router_applyRampUpdates is RouterSetup { ); } - function test_Fuzz_OffRampUpdates( + function testFuzz_OffRampUpdates( address[20] memory offRampsInput ) public { Router.OffRamp[] memory offRamps = new Router.OffRamp[](20); @@ -219,7 +219,7 @@ contract Router_applyRampUpdates is RouterSetup { } } - function test_Fuzz_OnRampUpdates( + function testFuzz_OnRampUpdates( Router.OnRamp[] memory onRamps ) public { // Test adding onRamps diff --git a/contracts/src/v0.8/ccip/test/router/Router/Router.setWrappedNative.t.sol b/contracts/src/v0.8/ccip/test/router/Router/Router.setWrappedNative.t.sol index 823aa8d144e..a23d98e4eaa 100644 --- a/contracts/src/v0.8/ccip/test/router/Router/Router.setWrappedNative.t.sol +++ b/contracts/src/v0.8/ccip/test/router/Router/Router.setWrappedNative.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.24; import {OnRampSetup} from "../../onRamp/OnRamp/OnRampSetup.t.sol"; contract Router_setWrappedNative is OnRampSetup { - function test_Fuzz_SetWrappedNative_Success( + function testFuzz_SetWrappedNative_Success( address wrappedNative ) public { s_sourceRouter.setWrappedNative(wrappedNative); diff --git a/contracts/src/v0.8/ccip/test/tokenAdminRegistry/TokenAdminRegistry/TokenAdminRegistry.getAllConfiguredTokens.t.sol b/contracts/src/v0.8/ccip/test/tokenAdminRegistry/TokenAdminRegistry/TokenAdminRegistry.getAllConfiguredTokens.t.sol index ab34fd3ab0a..6e16f27eca7 100644 --- a/contracts/src/v0.8/ccip/test/tokenAdminRegistry/TokenAdminRegistry/TokenAdminRegistry.getAllConfiguredTokens.t.sol +++ b/contracts/src/v0.8/ccip/test/tokenAdminRegistry/TokenAdminRegistry/TokenAdminRegistry.getAllConfiguredTokens.t.sol @@ -5,7 +5,7 @@ import {TokenAdminRegistry} from "../../../tokenAdminRegistry/TokenAdminRegistry import {TokenAdminRegistrySetup} from "./TokenAdminRegistrySetup.t.sol"; contract TokenAdminRegistry_getAllConfiguredTokens is TokenAdminRegistrySetup { - function test_Fuzz_getAllConfiguredTokens_Success( + function testFuzz_getAllConfiguredTokens_Success( uint8 numberOfTokens ) public { TokenAdminRegistry cleanTokenAdminRegistry = new TokenAdminRegistry(); diff --git a/contracts/src/v0.8/ccip/test/tokenAdminRegistry/TokenAdminRegistry/TokenAdminRegistry.proposeAdministrator.t.sol b/contracts/src/v0.8/ccip/test/tokenAdminRegistry/TokenAdminRegistry/TokenAdminRegistry.proposeAdministrator.t.sol index c1be3a27b13..6f3ac4449c6 100644 --- a/contracts/src/v0.8/ccip/test/tokenAdminRegistry/TokenAdminRegistry/TokenAdminRegistry.proposeAdministrator.t.sol +++ b/contracts/src/v0.8/ccip/test/tokenAdminRegistry/TokenAdminRegistry/TokenAdminRegistry.proposeAdministrator.t.sol @@ -69,7 +69,7 @@ contract TokenAdminRegistry_proposeAdministrator is TokenAdminRegistrySetup { mapping(address token => address admin) internal s_AdminByToken; - function test_Fuzz_proposeAdministrator_Success(address[50] memory tokens, address[50] memory admins) public { + function testFuzz_proposeAdministrator_Success(address[50] memory tokens, address[50] memory admins) public { TokenAdminRegistry cleanTokenAdminRegistry = new TokenAdminRegistry(); for (uint256 i = 0; i < tokens.length; i++) { if (admins[i] == address(0)) { diff --git a/contracts/src/v0.8/operatorforwarder/test/Forwarder.t.sol b/contracts/src/v0.8/operatorforwarder/test/Forwarder.t.sol index ba6ce1c17c1..cdc38080ae2 100644 --- a/contracts/src/v0.8/operatorforwarder/test/Forwarder.t.sol +++ b/contracts/src/v0.8/operatorforwarder/test/Forwarder.t.sol @@ -70,7 +70,7 @@ contract ForwarderTest is Deployer { require(returnedSenders[0] == senders[0]); } - function test_Forward_Success(uint256 _value) public { + function testFuzz_Forward_Success(uint256 _value) public { _addSenders(); vm.expectRevert("Not authorized sender"); @@ -98,7 +98,7 @@ contract ForwarderTest is Deployer { require(s_mockReceiver.getValue() == _value); } - function test_MultiForward_Success(uint256 _value1, uint256 _value2) public { + function testFuzz_MultiForward_Success(uint256 _value1, uint256 _value2) public { _addSenders(); address[] memory tos; diff --git a/contracts/src/v0.8/operatorforwarder/test/operator.t.sol b/contracts/src/v0.8/operatorforwarder/test/operator.t.sol index 6c4a7c2ae1a..870238b5e93 100644 --- a/contracts/src/v0.8/operatorforwarder/test/operator.t.sol +++ b/contracts/src/v0.8/operatorforwarder/test/operator.t.sol @@ -23,7 +23,7 @@ contract OperatorTest is Deployer { s_callback = new Callback(address(s_operator)); } - function test_SendRequest_Success(uint96 payment) public { + function testFuzz_SendRequest_Success(uint96 payment) public { vm.assume(payment > 0); deal(address(s_link), address(s_client), payment); // We're going to cancel one request and fulfill the other @@ -47,7 +47,7 @@ contract OperatorTest is Deployer { assertEq(s_link.balanceOf(address(s_client)), payment); } - function test_SendRequestAndCancelRequest_Success(uint96 payment) public { + function testFuzz_SendRequestAndCancelRequest_Success(uint96 payment) public { vm.assume(payment > 1); payment /= payment; diff --git a/contracts/src/v0.8/shared/test/call/CallWithExactGas.t.sol b/contracts/src/v0.8/shared/test/call/CallWithExactGas.t.sol index b432de58a5f..9d1a8e35ce5 100644 --- a/contracts/src/v0.8/shared/test/call/CallWithExactGas.t.sol +++ b/contracts/src/v0.8/shared/test/call/CallWithExactGas.t.sol @@ -26,7 +26,7 @@ contract CallWithExactGasSetup is BaseTest { } contract CallWithExactGas__callWithExactGas is CallWithExactGasSetup { - function test_callWithExactGasSuccess(bytes memory payload, bytes4 funcSelector) public { + function testFuzz_callWithExactGasSuccess(bytes memory payload, bytes4 funcSelector) public { vm.pauseGasMetering(); bytes memory data = abi.encodeWithSelector(funcSelector, payload); @@ -220,7 +220,7 @@ contract CallWithExactGas__callWithExactGasSafeReturnData is CallWithExactGasSet assertGt(gasUsed, 500); } - function test_Fuzz_CallWithExactGasSafeReturnData_ConsumeAllGas_Success(uint8 gasLimitMultiplier) external { + function testFuzz_CallWithExactGasSafeReturnData_ConsumeAllGas_Success(uint8 gasLimitMultiplier) external { vm.assume(gasLimitMultiplier > 0); // Assume not zero to avoid zero gas being passed to s_gasConsumer uint16 maxRetBytes = 0; @@ -368,7 +368,7 @@ contract CallWithExactGas__callWithExactGasSafeReturnData is CallWithExactGasSet } contract CallWithExactGas__callWithExactGasEvenIfTargetIsNoContract is CallWithExactGasSetup { - function test_CallWithExactGasEvenIfTargetIsNoContractSuccess(bytes memory payload, bytes4 funcSelector) public { + function testFuzz_CallWithExactGasEvenIfTargetIsNoContractSuccess(bytes memory payload, bytes4 funcSelector) public { vm.pauseGasMetering(); bytes memory data = abi.encodeWithSelector(funcSelector, payload); vm.assume( From 7bd35dcea04b02ceb2e46a0431eca61ab3b78889 Mon Sep 17 00:00:00 2001 From: ilija42 <57732589+ilija42@users.noreply.github.com> Date: Wed, 13 Nov 2024 00:18:39 +0100 Subject: [PATCH 04/14] Bump chainlink-ccip and common and update Contract Reader CCIP cfgs (#15137) * Bump chainlink-ccip and common and update Contract Reader CCIP cfgs * Add changest * Update ccip reader configs * Improve TestCCIPReader_MsgsBetweenSeqNums test * Bump ccip --- .changeset/many-carrots-share.md | 5 +++++ .../ccipreader/ccipreader_test.go | 16 ++++++++++++++-- .../ccip/configs/evm/contract_reader.go | 8 ++++++++ core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- deployment/go.mod | 2 +- deployment/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 ++-- 13 files changed, 42 insertions(+), 17 deletions(-) create mode 100644 .changeset/many-carrots-share.md diff --git a/.changeset/many-carrots-share.md b/.changeset/many-carrots-share.md new file mode 100644 index 00000000000..da22ac6ed4f --- /dev/null +++ b/.changeset/many-carrots-share.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +#internal Update ccip contract reader cfg for ccip message sent to use output codec wrapper modifier diff --git a/core/capabilities/ccip/ccip_integration_tests/ccipreader/ccipreader_test.go b/core/capabilities/ccip/ccip_integration_tests/ccipreader/ccipreader_test.go index 6c8a5ee415d..150a51f93fb 100644 --- a/core/capabilities/ccip/ccip_integration_tests/ccipreader/ccipreader_test.go +++ b/core/capabilities/ccip/ccip_integration_tests/ccipreader/ccipreader_test.go @@ -18,6 +18,7 @@ import ( "golang.org/x/exp/maps" cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink-common/pkg/codec" "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" @@ -260,6 +261,13 @@ func TestCCIPReader_MsgsBetweenSeqNums(t *testing.T) { consts.EventAttributeSequenceNumber: {Name: "message.header.sequenceNumber"}, }, }, + OutputModifications: codec.ModifiersConfig{ + &codec.WrapperModifierConfig{Fields: map[string]string{ + "Message.FeeTokenAmount": "Int", + "Message.FeeValueJuels": "Int", + "Message.TokenAmounts.Amount": "Int", + }}, + }, }, }, }, @@ -282,7 +290,7 @@ func TestCCIPReader_MsgsBetweenSeqNums(t *testing.T) { FeeToken: utils.RandomAddress(), FeeTokenAmount: big.NewInt(1), FeeValueJuels: big.NewInt(2), - TokenAmounts: make([]ccip_reader_tester.InternalEVM2AnyTokenTransfer, 0), + TokenAmounts: []ccip_reader_tester.InternalEVM2AnyTokenTransfer{{Amount: big.NewInt(1)}, {Amount: big.NewInt(2)}}, }) assert.NoError(t, err) @@ -300,7 +308,7 @@ func TestCCIPReader_MsgsBetweenSeqNums(t *testing.T) { FeeToken: utils.RandomAddress(), FeeTokenAmount: big.NewInt(3), FeeValueJuels: big.NewInt(4), - TokenAmounts: make([]ccip_reader_tester.InternalEVM2AnyTokenTransfer, 0), + TokenAmounts: []ccip_reader_tester.InternalEVM2AnyTokenTransfer{{Amount: big.NewInt(3)}, {Amount: big.NewInt(4)}}, }) assert.NoError(t, err) @@ -329,10 +337,14 @@ func TestCCIPReader_MsgsBetweenSeqNums(t *testing.T) { require.Equal(t, cciptypes.SeqNum(10), msgs[0].Header.SequenceNumber) require.Equal(t, big.NewInt(1), msgs[0].FeeTokenAmount.Int) require.Equal(t, big.NewInt(2), msgs[0].FeeValueJuels.Int) + require.Equal(t, int64(1), msgs[0].TokenAmounts[0].Amount.Int64()) + require.Equal(t, int64(2), msgs[0].TokenAmounts[1].Amount.Int64()) require.Equal(t, cciptypes.SeqNum(15), msgs[1].Header.SequenceNumber) require.Equal(t, big.NewInt(3), msgs[1].FeeTokenAmount.Int) require.Equal(t, big.NewInt(4), msgs[1].FeeValueJuels.Int) + require.Equal(t, int64(3), msgs[1].TokenAmounts[0].Amount.Int64()) + require.Equal(t, int64(4), msgs[1].TokenAmounts[1].Amount.Int64()) for _, msg := range msgs { require.Equal(t, chainS1, msg.Header.SourceChainSelector) diff --git a/core/capabilities/ccip/configs/evm/contract_reader.go b/core/capabilities/ccip/configs/evm/contract_reader.go index 7cbc4a9fa8d..dc0f257c713 100644 --- a/core/capabilities/ccip/configs/evm/contract_reader.go +++ b/core/capabilities/ccip/configs/evm/contract_reader.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/smartcontractkit/chainlink-common/pkg/codec" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_home" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_proxy_contract" @@ -228,6 +229,13 @@ var SourceReaderConfig = evmrelaytypes.ChainReaderConfig{ consts.EventAttributeSequenceNumber: {Name: "message.header.sequenceNumber"}, }, }, + OutputModifications: codec.ModifiersConfig{ + &codec.WrapperModifierConfig{Fields: map[string]string{ + "Message.FeeTokenAmount": "Int", + "Message.FeeValueJuels": "Int", + "Message.TokenAmounts.Amount": "Int", + }}, + }, }, consts.MethodNameOnRampGetStaticConfig: { ChainSpecificName: mustGetMethodName("getStaticConfig", onrampABI), diff --git a/core/scripts/go.mod b/core/scripts/go.mod index c713442cb06..6de43b49e55 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -294,7 +294,7 @@ require ( github.com/shirou/gopsutil/v3 v3.24.3 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240926212305-a6deabdfce86 // indirect github.com/smartcontractkit/chain-selectors v1.0.27 // indirect - github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 // indirect + github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b // indirect github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 574647034ac..3a7f6db8076 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1092,8 +1092,8 @@ github.com/smartcontractkit/chain-selectors v1.0.27 h1:VE/ftX9Aae4gnw67yR1raKi+3 github.com/smartcontractkit/chain-selectors v1.0.27/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 h1:BeLnOf2KKQpJj9nzfnE7QEg9ZqJ2jy/sbpNYVixVM2Y= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b h1:4kmZtaQ4fXwduHnw9xk5VmiIOW4nHg/Mx6iidlZJt5o= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 h1:yJNBWCdNL/X8+wEs3TGTBe9gssMmw5FTFxxrlo+0mVo= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= diff --git a/deployment/go.mod b/deployment/go.mod index 320e7670d72..c9da65fd6c6 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -23,7 +23,7 @@ require ( github.com/sethvargo/go-retry v0.2.4 github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240926212305-a6deabdfce86 github.com/smartcontractkit/chain-selectors v1.0.27 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 + github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 diff --git a/deployment/go.sum b/deployment/go.sum index 77809c8059b..38bcb4b96a1 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1382,8 +1382,8 @@ github.com/smartcontractkit/chain-selectors v1.0.27 h1:VE/ftX9Aae4gnw67yR1raKi+3 github.com/smartcontractkit/chain-selectors v1.0.27/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 h1:BeLnOf2KKQpJj9nzfnE7QEg9ZqJ2jy/sbpNYVixVM2Y= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b h1:4kmZtaQ4fXwduHnw9xk5VmiIOW4nHg/Mx6iidlZJt5o= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 h1:yJNBWCdNL/X8+wEs3TGTBe9gssMmw5FTFxxrlo+0mVo= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= diff --git a/go.mod b/go.mod index 28d6920bcd9..c96444a4260 100644 --- a/go.mod +++ b/go.mod @@ -76,7 +76,7 @@ require ( github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chain-selectors v1.0.27 github.com/smartcontractkit/chainlink-automation v0.8.1 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 + github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e diff --git a/go.sum b/go.sum index de6fdf996f2..c927d19fcfb 100644 --- a/go.sum +++ b/go.sum @@ -1076,8 +1076,8 @@ github.com/smartcontractkit/chain-selectors v1.0.27 h1:VE/ftX9Aae4gnw67yR1raKi+3 github.com/smartcontractkit/chain-selectors v1.0.27/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 h1:BeLnOf2KKQpJj9nzfnE7QEg9ZqJ2jy/sbpNYVixVM2Y= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b h1:4kmZtaQ4fXwduHnw9xk5VmiIOW4nHg/Mx6iidlZJt5o= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 h1:yJNBWCdNL/X8+wEs3TGTBe9gssMmw5FTFxxrlo+0mVo= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 985710ad69a..1d5211adfe4 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -36,7 +36,7 @@ require ( github.com/slack-go/slack v0.15.0 github.com/smartcontractkit/chain-selectors v1.0.27 github.com/smartcontractkit/chainlink-automation v0.8.1 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 + github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.2 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index a5c2fa81a44..682f4bd70f8 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1403,8 +1403,8 @@ github.com/smartcontractkit/chain-selectors v1.0.27 h1:VE/ftX9Aae4gnw67yR1raKi+3 github.com/smartcontractkit/chain-selectors v1.0.27/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 h1:BeLnOf2KKQpJj9nzfnE7QEg9ZqJ2jy/sbpNYVixVM2Y= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b h1:4kmZtaQ4fXwduHnw9xk5VmiIOW4nHg/Mx6iidlZJt5o= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 h1:yJNBWCdNL/X8+wEs3TGTBe9gssMmw5FTFxxrlo+0mVo= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 539e7a2bccc..780b2daf4a6 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -65,7 +65,7 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 // indirect + github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b // indirect github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f // indirect github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.2 // indirect github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 83d8b0ee21f..3d849414c2c 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1392,8 +1392,8 @@ github.com/smartcontractkit/chain-selectors v1.0.27 h1:VE/ftX9Aae4gnw67yR1raKi+3 github.com/smartcontractkit/chain-selectors v1.0.27/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 h1:BeLnOf2KKQpJj9nzfnE7QEg9ZqJ2jy/sbpNYVixVM2Y= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b h1:4kmZtaQ4fXwduHnw9xk5VmiIOW4nHg/Mx6iidlZJt5o= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 h1:yJNBWCdNL/X8+wEs3TGTBe9gssMmw5FTFxxrlo+0mVo= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= From 61aa9afd6b25ae50df336cae994c0070934707ea Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Tue, 12 Nov 2024 17:56:57 -0600 Subject: [PATCH 05/14] core/services/relay/evm: fix commit race (#15212) --- core/services/relay/evm/chain_components_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/services/relay/evm/chain_components_test.go b/core/services/relay/evm/chain_components_test.go index 91e41295e48..3efa50d1ec5 100644 --- a/core/services/relay/evm/chain_components_test.go +++ b/core/services/relay/evm/chain_components_test.go @@ -236,7 +236,6 @@ func (h *helper) Init(t *testing.T) { h.client = h.Client(t) h.txm = h.TXM(t, h.client) - h.Commit() } func (h *helper) SetupKeys(t *testing.T) { From 3b3b86ceaed419fa3890be17c8699a3416081fb9 Mon Sep 17 00:00:00 2001 From: Matthew Kelly Date: Wed, 13 Nov 2024 22:52:27 +0800 Subject: [PATCH 06/14] Add donID to mercury EA telemetry (#15197) * Add donID to mercury EA telemetry * Add changeset * Update changeset * Fix lint issue * Add donID to logging --- .changeset/nine-stingrays-march.md | 5 +++ core/services/llo/delegate.go | 7 ++-- core/services/llo/telemetry.go | 9 +++-- core/services/llo/telemetry_test.go | 8 +++-- core/services/ocr2/delegate.go | 1 + .../telem/telem_enhanced_ea_mercury.pb.go | 33 ++++++++++++------- .../telem/telem_enhanced_ea_mercury.proto | 1 + 7 files changed, 43 insertions(+), 21 deletions(-) create mode 100644 .changeset/nine-stingrays-march.md diff --git a/.changeset/nine-stingrays-march.md b/.changeset/nine-stingrays-march.md new file mode 100644 index 00000000000..c2f88d95663 --- /dev/null +++ b/.changeset/nine-stingrays-march.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +Add don_id to Mercury Enhanced EA telemetry #added diff --git a/core/services/llo/delegate.go b/core/services/llo/delegate.go index 3380b4f1bc5..f5f9b5f05f1 100644 --- a/core/services/llo/delegate.go +++ b/core/services/llo/delegate.go @@ -57,6 +57,7 @@ type DelegateConfig struct { RetirementReportCodec datastreamsllo.RetirementReportCodec ShouldRetireCache datastreamsllo.ShouldRetireCache EAMonitoringEndpoint ocrcommontypes.MonitoringEndpoint + DonID uint32 // OCR3 TraceLogging bool @@ -74,7 +75,7 @@ type DelegateConfig struct { } func NewDelegate(cfg DelegateConfig) (job.ServiceCtx, error) { - lggr := logger.Sugared(cfg.Logger).With("jobName", cfg.JobName.ValueOrZero()) + lggr := logger.Sugared(cfg.Logger).With("jobName", cfg.JobName.ValueOrZero(), "donID", cfg.DonID) if cfg.DataSource == nil { return nil, errors.New("DataSource must not be nil") } @@ -94,7 +95,7 @@ func NewDelegate(cfg DelegateConfig) (job.ServiceCtx, error) { var t TelemeterService if cfg.CaptureEATelemetry { - t = NewTelemeterService(lggr, cfg.EAMonitoringEndpoint) + t = NewTelemeterService(lggr, cfg.EAMonitoringEndpoint, cfg.DonID) } else { t = NullTelemeter } @@ -110,7 +111,7 @@ func (d *delegate) Start(ctx context.Context) error { return fmt.Errorf("expected either 1 or 2 ContractConfigTrackers, got: %d", len(d.cfg.ContractConfigTrackers)) } - d.cfg.Logger.Debugw("Starting LLO job", "instances", len(d.cfg.ContractConfigTrackers), "jobName", d.cfg.JobName.ValueOrZero(), "captureEATelemetry", d.cfg.CaptureEATelemetry) + d.cfg.Logger.Debugw("Starting LLO job", "instances", len(d.cfg.ContractConfigTrackers), "jobName", d.cfg.JobName.ValueOrZero(), "captureEATelemetry", d.cfg.CaptureEATelemetry, "donID", d.cfg.DonID) var merr error diff --git a/core/services/llo/telemetry.go b/core/services/llo/telemetry.go index d5c113c61ef..888ee9d5d36 100644 --- a/core/services/llo/telemetry.go +++ b/core/services/llo/telemetry.go @@ -31,18 +31,19 @@ type TelemeterService interface { services.Service } -func NewTelemeterService(lggr logger.Logger, monitoringEndpoint commontypes.MonitoringEndpoint) TelemeterService { +func NewTelemeterService(lggr logger.Logger, monitoringEndpoint commontypes.MonitoringEndpoint, donID uint32) TelemeterService { if monitoringEndpoint == nil { return NullTelemeter } - return newTelemeter(lggr, monitoringEndpoint) + return newTelemeter(lggr, monitoringEndpoint, donID) } -func newTelemeter(lggr logger.Logger, monitoringEndpoint commontypes.MonitoringEndpoint) *telemeter { +func newTelemeter(lggr logger.Logger, monitoringEndpoint commontypes.MonitoringEndpoint, donID uint32) *telemeter { chTelemetryObservation := make(chan TelemetryObservation, 100) t := &telemeter{ chTelemetryObservation: chTelemetryObservation, monitoringEndpoint: monitoringEndpoint, + donID: donID, } t.Service, t.eng = services.Config{ Name: "LLOTelemeterService", @@ -58,6 +59,7 @@ type telemeter struct { monitoringEndpoint commontypes.MonitoringEndpoint chTelemetryObservation chan TelemetryObservation + donID uint32 } func (t *telemeter) EnqueueV3PremiumLegacy(run *pipeline.Run, trrs pipeline.TaskRunResults, streamID uint32, opts llo.DSOpts, val llo.StreamValue, err error) { @@ -140,6 +142,7 @@ func (t *telemeter) collectV3PremiumLegacyTelemetry(d TelemetryObservation) { Epoch: int64(epoch), AssetSymbol: eaTelem.AssetSymbol, Version: uint32(1000 + mercuryutils.REPORT_V3), // add 1000 to distinguish between legacy feeds, this can be changed if necessary + DonId: t.donID, } bytes, err := proto.Marshal(tea) diff --git a/core/services/llo/telemetry_test.go b/core/services/llo/telemetry_test.go index ec77e959d24..ec650bedb83 100644 --- a/core/services/llo/telemetry_test.go +++ b/core/services/llo/telemetry_test.go @@ -112,10 +112,11 @@ func Test_Telemeter(t *testing.T) { run := &pipeline.Run{ID: 42} streamID := uint32(135) + donID := uint32(1) opts := &mockOpts{} t.Run("with error", func(t *testing.T) { - tm := newTelemeter(lggr, m) + tm := newTelemeter(lggr, m, donID) servicetest.Run(t, tm) t.Run("if error is some random failure returns immediately", func(t *testing.T) { @@ -142,7 +143,7 @@ func Test_Telemeter(t *testing.T) { }) }) t.Run("with decimal value, sets all values correctly", func(t *testing.T) { - tm := newTelemeter(lggr, m) + tm := newTelemeter(lggr, m, donID) val := llo.ToDecimal(decimal.NewFromFloat32(102.12)) servicetest.Run(t, tm) tm.EnqueueV3PremiumLegacy(run, trrs, streamID, opts, val, nil) @@ -184,6 +185,7 @@ func Test_Telemeter(t *testing.T) { assert.Equal(t, int64(18), decoded.Round) assert.Equal(t, int64(4), decoded.Epoch) assert.Equal(t, "eth/usd", decoded.AssetSymbol) + assert.Equal(t, uint32(1), decoded.DonId) if i == 2 { return } @@ -191,7 +193,7 @@ func Test_Telemeter(t *testing.T) { } }) t.Run("with quote value", func(t *testing.T) { - tm := newTelemeter(lggr, m) + tm := newTelemeter(lggr, m, donID) val := &llo.Quote{Bid: decimal.NewFromFloat32(102.12), Benchmark: decimal.NewFromFloat32(103.32), Ask: decimal.NewFromFloat32(104.25)} servicetest.Run(t, tm) tm.EnqueueV3PremiumLegacy(run, trrs, streamID, opts, val, nil) diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index 371eccdbe89..acee4168a5a 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -1050,6 +1050,7 @@ func (d *Delegate) newServicesLLO( ShouldRetireCache: provider.ShouldRetireCache(), RetirementReportCodec: datastreamsllo.StandardRetirementReportCodec{}, EAMonitoringEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, telemetryContractID, synchronization.EnhancedEAMercury), + DonID: pluginCfg.DonID, TraceLogging: d.cfg.OCR2().TraceLogging(), BinaryNetworkEndpointFactory: d.peerWrapper.Peer2, diff --git a/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go b/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go index 09eed12ee8a..34f4b3e349b 100644 --- a/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go +++ b/core/services/synchronization/telem/telem_enhanced_ea_mercury.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.2 -// protoc v5.28.0 +// protoc v5.28.3 // source: core/services/synchronization/telem/telem_enhanced_ea_mercury.proto package telem @@ -115,6 +115,7 @@ type EnhancedEAMercury struct { Round int64 `protobuf:"varint,19,opt,name=round,proto3" json:"round,omitempty"` Epoch int64 `protobuf:"varint,20,opt,name=epoch,proto3" json:"epoch,omitempty"` AssetSymbol string `protobuf:"bytes,21,opt,name=asset_symbol,json=assetSymbol,proto3" json:"asset_symbol,omitempty"` + DonId uint32 `protobuf:"varint,36,opt,name=don_id,json=donId,proto3" json:"don_id,omitempty"` } func (x *EnhancedEAMercury) Reset() { @@ -394,6 +395,13 @@ func (x *EnhancedEAMercury) GetAssetSymbol() string { return "" } +func (x *EnhancedEAMercury) GetDonId() uint32 { + if x != nil { + return x.DonId + } + return 0 +} + var File_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto protoreflect.FileDescriptor var file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_rawDesc = []byte{ @@ -401,7 +409,7 @@ var file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_raw 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x5f, 0x65, 0x6e, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x5f, 0x65, 0x61, 0x5f, 0x6d, 0x65, 0x72, 0x63, 0x75, 0x72, 0x79, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x22, 0xaa, 0x0d, 0x0a, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x22, 0xc1, 0x0d, 0x0a, 0x11, 0x45, 0x6e, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x45, 0x41, 0x4d, 0x65, 0x72, 0x63, 0x75, 0x72, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, @@ -508,16 +516,17 @@ var file_core_services_synchronization_telem_telem_enhanced_ea_mercury_proto_raw 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x14, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x73, - 0x73, 0x65, 0x74, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x2a, 0x31, 0x0a, 0x0c, 0x4d, 0x61, 0x72, - 0x6b, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, - 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x44, - 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4f, 0x50, 0x45, 0x4e, 0x10, 0x02, 0x42, 0x4e, 0x5a, 0x4c, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x6d, 0x61, 0x72, 0x74, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, 0x69, 0x74, 0x2f, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x65, 0x74, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x12, 0x15, 0x0a, 0x06, 0x64, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x24, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x64, 0x6f, 0x6e, 0x49, 0x64, + 0x2a, 0x31, 0x0a, 0x0c, 0x4d, 0x61, 0x72, 0x6b, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, + 0x06, 0x43, 0x4c, 0x4f, 0x53, 0x45, 0x44, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4f, 0x50, 0x45, + 0x4e, 0x10, 0x02, 0x42, 0x4e, 0x5a, 0x4c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x73, 0x6d, 0x61, 0x72, 0x74, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x6b, + 0x69, 0x74, 0x2f, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x6b, 0x2f, 0x76, 0x32, 0x2f, + 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x79, + 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x74, 0x65, + 0x6c, 0x65, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto b/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto index d57b7ca836a..cfb8dbac0c9 100644 --- a/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto +++ b/core/services/synchronization/telem/telem_enhanced_ea_mercury.proto @@ -59,4 +59,5 @@ message EnhancedEAMercury { int64 round=19; int64 epoch=20; string asset_symbol=21; + uint32 don_id=36; } From 1a9f8ccbbe950dc97b5027e9223d51308aa63366 Mon Sep 17 00:00:00 2001 From: Cedric Date: Wed, 13 Nov 2024 15:35:50 +0000 Subject: [PATCH 07/14] Add worker pool to WASM capability (#15088) * [chore] Add worker pool to compute capability - Also add step-level timeout to engine. This was removed when we moved away from ExecuteSync(). * WIP * Some more comments --- core/capabilities/compute/compute.go | 119 +++++++++++++++--- core/capabilities/compute/compute_test.go | 20 +-- core/capabilities/compute/transformer.go | 54 ++++---- core/capabilities/compute/transformer_test.go | 21 +++- .../services/standardcapabilities/delegate.go | 8 +- core/services/workflows/engine.go | 13 +- core/services/workflows/engine_test.go | 32 ++--- 7 files changed, 196 insertions(+), 71 deletions(-) diff --git a/core/capabilities/compute/compute.go b/core/capabilities/compute/compute.go index 7e6961d2e8a..78a4cc1e033 100644 --- a/core/capabilities/compute/compute.go +++ b/core/capabilities/compute/compute.go @@ -8,6 +8,7 @@ import ( "fmt" "net/http" "strings" + "sync" "time" "github.com/google/uuid" @@ -19,6 +20,7 @@ import ( capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" "github.com/smartcontractkit/chainlink-common/pkg/custmsg" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/services" coretypes "github.com/smartcontractkit/chainlink-common/pkg/types/core" "github.com/smartcontractkit/chainlink-common/pkg/workflows/wasm/host" wasmpb "github.com/smartcontractkit/chainlink-common/pkg/workflows/wasm/pb" @@ -73,7 +75,8 @@ var ( var _ capabilities.ActionCapability = (*Compute)(nil) type Compute struct { - log logger.Logger + stopCh services.StopChan + log logger.Logger // emitter is used to emit messages from the WASM module to a configured collector. emitter custmsg.MessageEmitter @@ -82,9 +85,13 @@ type Compute struct { // transformer is used to transform a values.Map into a ParsedConfig struct on each execution // of a request. - transformer ConfigTransformer + transformer *transformer outgoingConnectorHandler *webapi.OutgoingConnectorHandler idGenerator func() string + + numWorkers int + queue chan request + wg sync.WaitGroup } func (c *Compute) RegisterToWorkflow(ctx context.Context, request capabilities.RegisterToWorkflowRequest) error { @@ -100,35 +107,76 @@ func generateID(binary []byte) string { return fmt.Sprintf("%x", id) } -func copyRequest(req capabilities.CapabilityRequest) capabilities.CapabilityRequest { - return capabilities.CapabilityRequest{ - Metadata: req.Metadata, - Inputs: req.Inputs.CopyMap(), - Config: req.Config.CopyMap(), +func (c *Compute) Execute(ctx context.Context, request capabilities.CapabilityRequest) (capabilities.CapabilityResponse, error) { + ch, err := c.enqueueRequest(ctx, request) + if err != nil { + return capabilities.CapabilityResponse{}, err + } + + select { + case <-c.stopCh: + return capabilities.CapabilityResponse{}, errors.New("service shutting down, aborting request") + case <-ctx.Done(): + return capabilities.CapabilityResponse{}, fmt.Errorf("request cancelled by upstream: %w", ctx.Err()) + case resp := <-ch: + return resp.resp, resp.err } } -func (c *Compute) Execute(ctx context.Context, request capabilities.CapabilityRequest) (capabilities.CapabilityResponse, error) { - copied := copyRequest(request) +type request struct { + ch chan response + req capabilities.CapabilityRequest + ctx func() context.Context +} - cfg, err := c.transformer.Transform(copied.Config) +type response struct { + resp capabilities.CapabilityResponse + err error +} + +func (c *Compute) enqueueRequest(ctx context.Context, req capabilities.CapabilityRequest) (<-chan response, error) { + ch := make(chan response) + r := request{ + ch: ch, + req: req, + ctx: func() context.Context { return ctx }, + } + select { + case <-c.stopCh: + return nil, errors.New("service shutting down, aborting request") + case <-ctx.Done(): + return nil, fmt.Errorf("could not enqueue request: %w", ctx.Err()) + case c.queue <- r: + return ch, nil + } +} + +func (c *Compute) execute(ctx context.Context, respCh chan response, req capabilities.CapabilityRequest) { + copiedReq, cfg, err := c.transformer.Transform(req) if err != nil { - return capabilities.CapabilityResponse{}, fmt.Errorf("invalid request: could not transform config: %w", err) + respCh <- response{err: fmt.Errorf("invalid request: could not transform config: %w", err)} + return } id := generateID(cfg.Binary) m, ok := c.modules.get(id) if !ok { - mod, err := c.initModule(id, cfg.ModuleConfig, cfg.Binary, request.Metadata) - if err != nil { - return capabilities.CapabilityResponse{}, err + mod, innerErr := c.initModule(id, cfg.ModuleConfig, cfg.Binary, copiedReq.Metadata) + if innerErr != nil { + respCh <- response{err: innerErr} + return } m = mod } - return c.executeWithModule(ctx, m.module, cfg.Config, request) + resp, err := c.executeWithModule(ctx, m.module, cfg.Config, copiedReq) + select { + case <-c.stopCh: + case <-ctx.Done(): + case respCh <- response{resp: resp, err: err}: + } } func (c *Compute) initModule(id string, cfg *host.ModuleConfig, binary []byte, requestMetadata capabilities.RequestMetadata) (*module, error) { @@ -196,11 +244,35 @@ func (c *Compute) Info(ctx context.Context) (capabilities.CapabilityInfo, error) func (c *Compute) Start(ctx context.Context) error { c.modules.start() + + c.wg.Add(c.numWorkers) + for i := 0; i < c.numWorkers; i++ { + go func() { + innerCtx, cancel := c.stopCh.NewCtx() + defer cancel() + + defer c.wg.Done() + c.worker(innerCtx) + }() + } return c.registry.Add(ctx, c) } +func (c *Compute) worker(ctx context.Context) { + for { + select { + case <-c.stopCh: + return + case req := <-c.queue: + c.execute(req.ctx(), req.ch, req.req) + } + } +} + func (c *Compute) Close() error { c.modules.close() + close(c.stopCh) + c.wg.Wait() return nil } @@ -270,18 +342,31 @@ func (c *Compute) createFetcher() func(ctx context.Context, req *wasmpb.FetchReq } } +const ( + defaultNumWorkers = 3 +) + +type Config struct { + webapi.ServiceConfig + NumWorkers int +} + func NewAction( - config webapi.ServiceConfig, + config Config, log logger.Logger, registry coretypes.CapabilitiesRegistry, handler *webapi.OutgoingConnectorHandler, idGenerator func() string, opts ...func(*Compute), ) *Compute { + if config.NumWorkers == 0 { + config.NumWorkers = defaultNumWorkers + } var ( lggr = logger.Named(log, "CustomCompute") labeler = custmsg.NewLabeler() compute = &Compute{ + stopCh: make(services.StopChan), log: lggr, emitter: labeler, registry: registry, @@ -289,6 +374,8 @@ func NewAction( transformer: NewTransformer(lggr, labeler), outgoingConnectorHandler: handler, idGenerator: idGenerator, + queue: make(chan request), + numWorkers: defaultNumWorkers, } ) diff --git a/core/capabilities/compute/compute_test.go b/core/capabilities/compute/compute_test.go index ec82533f2bb..719bff82edf 100644 --- a/core/capabilities/compute/compute_test.go +++ b/core/capabilities/compute/compute_test.go @@ -32,12 +32,14 @@ const ( validRequestUUID = "d2fe6db9-beb4-47c9-b2d6-d3065ace111e" ) -var defaultConfig = webapi.ServiceConfig{ - RateLimiter: common.RateLimiterConfig{ - GlobalRPS: 100.0, - GlobalBurst: 100, - PerSenderRPS: 100.0, - PerSenderBurst: 100, +var defaultConfig = Config{ + ServiceConfig: webapi.ServiceConfig{ + RateLimiter: common.RateLimiterConfig{ + GlobalRPS: 100.0, + GlobalBurst: 100, + PerSenderRPS: 100.0, + PerSenderBurst: 100, + }, }, } @@ -45,17 +47,17 @@ type testHarness struct { registry *corecapabilities.Registry connector *gcmocks.GatewayConnector log logger.Logger - config webapi.ServiceConfig + config Config connectorHandler *webapi.OutgoingConnectorHandler compute *Compute } -func setup(t *testing.T, config webapi.ServiceConfig) testHarness { +func setup(t *testing.T, config Config) testHarness { log := logger.TestLogger(t) registry := capabilities.NewRegistry(log) connector := gcmocks.NewGatewayConnector(t) idGeneratorFn := func() string { return validRequestUUID } - connectorHandler, err := webapi.NewOutgoingConnectorHandler(connector, config, ghcapabilities.MethodComputeAction, log) + connectorHandler, err := webapi.NewOutgoingConnectorHandler(connector, config.ServiceConfig, ghcapabilities.MethodComputeAction, log) require.NoError(t, err) compute := NewAction(config, log, registry, connectorHandler, idGeneratorFn) diff --git a/core/capabilities/compute/transformer.go b/core/capabilities/compute/transformer.go index 99efcda8323..3b4ae4cfa69 100644 --- a/core/capabilities/compute/transformer.go +++ b/core/capabilities/compute/transformer.go @@ -5,21 +5,13 @@ import ( "fmt" "time" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/custmsg" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/values" "github.com/smartcontractkit/chainlink-common/pkg/workflows/wasm/host" ) -type Transformer[T any, U any] interface { - // Transform changes a struct of type T into a struct of type U. Accepts a variadic list of options to modify the - // output struct. - Transform(T, ...func(*U)) (*U, error) -} - -// ConfigTransformer is a Transformer that converts a values.Map into a ParsedConfig struct. -type ConfigTransformer = Transformer[*values.Map, ParsedConfig] - // ParsedConfig is a struct that contains the binary and config for a wasm module, as well as the module config. type ParsedConfig struct { Binary []byte @@ -36,25 +28,41 @@ type transformer struct { emitter custmsg.MessageEmitter } +func shallowCopy(m *values.Map) *values.Map { + to := values.EmptyMap() + + for k, v := range m.Underlying { + to.Underlying[k] = v + } + + return to +} + // Transform attempts to read a valid ParsedConfig from an arbitrary values map. The map must // contain the binary and config keys. Optionally the map may specify wasm module specific // configuration values such as maxMemoryMBs, timeout, and tickInterval. Default logger and // emitter for the module are taken from the transformer instance. Override these values with // the functional options. -func (t *transformer) Transform(in *values.Map, opts ...func(*ParsedConfig)) (*ParsedConfig, error) { - binary, err := popValue[[]byte](in, binaryKey) +func (t *transformer) Transform(req capabilities.CapabilityRequest, opts ...func(*ParsedConfig)) (capabilities.CapabilityRequest, *ParsedConfig, error) { + copiedReq := capabilities.CapabilityRequest{ + Inputs: req.Inputs, + Metadata: req.Metadata, + Config: shallowCopy(req.Config), + } + + binary, err := popValue[[]byte](copiedReq.Config, binaryKey) if err != nil { - return nil, NewInvalidRequestError(err) + return capabilities.CapabilityRequest{}, nil, NewInvalidRequestError(err) } - config, err := popValue[[]byte](in, configKey) + config, err := popValue[[]byte](copiedReq.Config, configKey) if err != nil { - return nil, NewInvalidRequestError(err) + return capabilities.CapabilityRequest{}, nil, NewInvalidRequestError(err) } - maxMemoryMBs, err := popOptionalValue[int64](in, maxMemoryMBsKey) + maxMemoryMBs, err := popOptionalValue[int64](copiedReq.Config, maxMemoryMBsKey) if err != nil { - return nil, NewInvalidRequestError(err) + return capabilities.CapabilityRequest{}, nil, NewInvalidRequestError(err) } mc := &host.ModuleConfig{ @@ -63,30 +71,30 @@ func (t *transformer) Transform(in *values.Map, opts ...func(*ParsedConfig)) (*P Labeler: t.emitter, } - timeout, err := popOptionalValue[string](in, timeoutKey) + timeout, err := popOptionalValue[string](copiedReq.Config, timeoutKey) if err != nil { - return nil, NewInvalidRequestError(err) + return capabilities.CapabilityRequest{}, nil, NewInvalidRequestError(err) } var td time.Duration if timeout != "" { td, err = time.ParseDuration(timeout) if err != nil { - return nil, NewInvalidRequestError(err) + return capabilities.CapabilityRequest{}, nil, NewInvalidRequestError(err) } mc.Timeout = &td } - tickInterval, err := popOptionalValue[string](in, tickIntervalKey) + tickInterval, err := popOptionalValue[string](copiedReq.Config, tickIntervalKey) if err != nil { - return nil, NewInvalidRequestError(err) + return capabilities.CapabilityRequest{}, nil, NewInvalidRequestError(err) } var ti time.Duration if tickInterval != "" { ti, err = time.ParseDuration(tickInterval) if err != nil { - return nil, NewInvalidRequestError(err) + return capabilities.CapabilityRequest{}, nil, NewInvalidRequestError(err) } mc.TickInterval = ti } @@ -101,7 +109,7 @@ func (t *transformer) Transform(in *values.Map, opts ...func(*ParsedConfig)) (*P opt(pc) } - return pc, nil + return copiedReq, pc, nil } func NewTransformer(lggr logger.Logger, emitter custmsg.MessageEmitter) *transformer { diff --git a/core/capabilities/compute/transformer_test.go b/core/capabilities/compute/transformer_test.go index 83131636462..ee77e20d6f6 100644 --- a/core/capabilities/compute/transformer_test.go +++ b/core/capabilities/compute/transformer_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/custmsg" "github.com/smartcontractkit/chainlink-common/pkg/values" "github.com/smartcontractkit/chainlink-common/pkg/workflows/wasm/host" @@ -94,6 +95,9 @@ func Test_transformer(t *testing.T) { "binary": []byte{0x01, 0x02, 0x03}, "config": []byte{0x04, 0x05, 0x06}, }) + giveReq := capabilities.CapabilityRequest{ + Config: giveMap, + } require.NoError(t, err) wantTO := 4 * time.Second @@ -110,7 +114,7 @@ func Test_transformer(t *testing.T) { } tf := NewTransformer(lgger, emitter) - gotConfig, err := tf.Transform(giveMap) + _, gotConfig, err := tf.Transform(giveReq) require.NoError(t, err) assert.Equal(t, wantConfig, gotConfig) @@ -121,6 +125,9 @@ func Test_transformer(t *testing.T) { "binary": []byte{0x01, 0x02, 0x03}, "config": []byte{0x04, 0x05, 0x06}, }) + giveReq := capabilities.CapabilityRequest{ + Config: giveMap, + } require.NoError(t, err) wantConfig := &ParsedConfig{ @@ -133,7 +140,7 @@ func Test_transformer(t *testing.T) { } tf := NewTransformer(lgger, emitter) - gotConfig, err := tf.Transform(giveMap) + _, gotConfig, err := tf.Transform(giveReq) require.NoError(t, err) assert.Equal(t, wantConfig, gotConfig) @@ -145,10 +152,13 @@ func Test_transformer(t *testing.T) { "binary": []byte{0x01, 0x02, 0x03}, "config": []byte{0x04, 0x05, 0x06}, }) + giveReq := capabilities.CapabilityRequest{ + Config: giveMap, + } require.NoError(t, err) tf := NewTransformer(lgger, emitter) - _, err = tf.Transform(giveMap) + _, _, err = tf.Transform(giveReq) require.Error(t, err) require.ErrorContains(t, err, "invalid request") @@ -160,10 +170,13 @@ func Test_transformer(t *testing.T) { "binary": []byte{0x01, 0x02, 0x03}, "config": []byte{0x04, 0x05, 0x06}, }) + giveReq := capabilities.CapabilityRequest{ + Config: giveMap, + } require.NoError(t, err) tf := NewTransformer(lgger, emitter) - _, err = tf.Transform(giveMap) + _, _, err = tf.Transform(giveReq) require.Error(t, err) require.ErrorContains(t, err, "invalid request") diff --git a/core/services/standardcapabilities/delegate.go b/core/services/standardcapabilities/delegate.go index 80a60c334fc..a92e082dead 100644 --- a/core/services/standardcapabilities/delegate.go +++ b/core/services/standardcapabilities/delegate.go @@ -237,14 +237,14 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) ([]job.Ser return nil, errors.New("config is empty") } - var fetchCfg webapi.ServiceConfig - err := toml.Unmarshal([]byte(spec.StandardCapabilitiesSpec.Config), &fetchCfg) + var cfg compute.Config + err := toml.Unmarshal([]byte(spec.StandardCapabilitiesSpec.Config), &cfg) if err != nil { return nil, err } lggr := d.logger.Named("ComputeAction") - handler, err := webapi.NewOutgoingConnectorHandler(d.gatewayConnectorWrapper.GetGatewayConnector(), fetchCfg, capabilities.MethodComputeAction, lggr) + handler, err := webapi.NewOutgoingConnectorHandler(d.gatewayConnectorWrapper.GetGatewayConnector(), cfg.ServiceConfig, capabilities.MethodComputeAction, lggr) if err != nil { return nil, err } @@ -253,7 +253,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) ([]job.Ser return uuid.New().String() } - computeSrvc := compute.NewAction(fetchCfg, log, d.registry, handler, idGeneratorFn) + computeSrvc := compute.NewAction(cfg, log, d.registry, handler, idGeneratorFn) return []job.ServiceCtx{computeSrvc}, nil } diff --git a/core/services/workflows/engine.go b/core/services/workflows/engine.go index 8e2cb8e34cb..e20af85540d 100644 --- a/core/services/workflows/engine.go +++ b/core/services/workflows/engine.go @@ -113,6 +113,7 @@ type Engine struct { newWorkerTimeout time.Duration maxExecutionDuration time.Duration heartbeatCadence time.Duration + stepTimeoutDuration time.Duration // testing lifecycle hook to signal when an execution is finished. onExecutionFinished func(string) @@ -755,7 +756,10 @@ func (e *Engine) workerForStepRequest(ctx context.Context, msg stepRequest) { // TODO ks-462 inputs logCustMsg(ctx, cma, "executing step", l) - inputs, outputs, err := e.executeStep(ctx, l, msg) + stepCtx, cancel := context.WithTimeout(ctx, e.stepTimeoutDuration) + defer cancel() + + inputs, outputs, err := e.executeStep(stepCtx, l, msg) var stepStatus string switch { case errors.Is(capabilities.ErrStopExecution, err): @@ -1137,6 +1141,7 @@ type Config struct { Binary []byte SecretsFetcher secretsFetcher HeartbeatCadence time.Duration + StepTimeout time.Duration // For testing purposes only maxRetries int @@ -1152,6 +1157,7 @@ const ( defaultNewWorkerTimeout = 2 * time.Second defaultMaxExecutionDuration = 10 * time.Minute defaultHeartbeatCadence = 5 * time.Minute + defaultStepTimeout = 2 * time.Minute ) func NewEngine(ctx context.Context, cfg Config) (engine *Engine, err error) { @@ -1183,6 +1189,10 @@ func NewEngine(ctx context.Context, cfg Config) (engine *Engine, err error) { cfg.HeartbeatCadence = defaultHeartbeatCadence } + if cfg.StepTimeout == 0 { + cfg.StepTimeout = defaultStepTimeout + } + if cfg.retryMs == 0 { cfg.retryMs = 5000 } @@ -1235,6 +1245,7 @@ func NewEngine(ctx context.Context, cfg Config) (engine *Engine, err error) { triggerEvents: make(chan capabilities.TriggerResponse), stopCh: make(chan struct{}), newWorkerTimeout: cfg.NewWorkerTimeout, + stepTimeoutDuration: cfg.StepTimeout, maxExecutionDuration: cfg.MaxExecutionDuration, heartbeatCadence: cfg.HeartbeatCadence, onExecutionFinished: cfg.onExecutionFinished, diff --git a/core/services/workflows/engine_test.go b/core/services/workflows/engine_test.go index 5e87d4f7603..e6667fe0bc6 100644 --- a/core/services/workflows/engine_test.go +++ b/core/services/workflows/engine_test.go @@ -1429,19 +1429,21 @@ func TestEngine_WithCustomComputeStep(t *testing.T) { ctx := testutils.Context(t) log := logger.TestLogger(t) reg := coreCap.NewRegistry(logger.TestLogger(t)) - cfg := webapi.ServiceConfig{ - RateLimiter: common.RateLimiterConfig{ - GlobalRPS: 100.0, - GlobalBurst: 100, - PerSenderRPS: 100.0, - PerSenderBurst: 100, + cfg := compute.Config{ + ServiceConfig: webapi.ServiceConfig{ + RateLimiter: common.RateLimiterConfig{ + GlobalRPS: 100.0, + GlobalBurst: 100, + PerSenderRPS: 100.0, + PerSenderBurst: 100, + }, }, } connector := gcmocks.NewGatewayConnector(t) handler, err := webapi.NewOutgoingConnectorHandler( connector, - cfg, + cfg.ServiceConfig, ghcapabilities.MethodComputeAction, log) require.NoError(t, err) @@ -1493,18 +1495,20 @@ func TestEngine_CustomComputePropagatesBreaks(t *testing.T) { ctx := testutils.Context(t) log := logger.TestLogger(t) reg := coreCap.NewRegistry(logger.TestLogger(t)) - cfg := webapi.ServiceConfig{ - RateLimiter: common.RateLimiterConfig{ - GlobalRPS: 100.0, - GlobalBurst: 100, - PerSenderRPS: 100.0, - PerSenderBurst: 100, + cfg := compute.Config{ + ServiceConfig: webapi.ServiceConfig{ + RateLimiter: common.RateLimiterConfig{ + GlobalRPS: 100.0, + GlobalBurst: 100, + PerSenderRPS: 100.0, + PerSenderBurst: 100, + }, }, } connector := gcmocks.NewGatewayConnector(t) handler, err := webapi.NewOutgoingConnectorHandler( connector, - cfg, + cfg.ServiceConfig, ghcapabilities.MethodComputeAction, log) require.NoError(t, err) From bb045250d163b0dd47d33e6ca35c252345b03da3 Mon Sep 17 00:00:00 2001 From: Makram Date: Wed, 13 Nov 2024 20:19:31 +0400 Subject: [PATCH 08/14] integration-tests/smoke: move ccip msging test (#15217) * integration-tests/smoke: move ccip msging test * fix imports * add messaging test to matrix * transform into docker based test --- .github/e2e-tests.yml | 16 +++- deployment/ccip/add_lane_test.go | 5 +- deployment/ccip/changeset/add_chain_test.go | 3 +- deployment/ccip/test_assertions.go | 55 ++++++++++-- deployment/ccip/test_helpers.go | 20 ++++- .../smoke/ccip_messaging_test.go | 84 +++++++++++++------ 6 files changed, 141 insertions(+), 42 deletions(-) rename deployment/ccip/changeset/messaging_test.go => integration-tests/smoke/ccip_messaging_test.go (71%) diff --git a/.github/e2e-tests.yml b/.github/e2e-tests.yml index 3b91bd251a1..aee250420e0 100644 --- a/.github/e2e-tests.yml +++ b/.github/e2e-tests.yml @@ -948,6 +948,20 @@ runner-test-matrix: test_env_vars: E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2 E2E_JD_VERSION: 0.4.0 + + - id: smoke/ccip_messaging_test.go:* + path: integration-tests/smoke/ccip_messaging_test.go + test_env_type: docker + runs_on: ubuntu-latest + triggers: + - PR E2E Core Tests + - Merge Queue E2E Core Tests + - Nightly E2E Tests + test_cmd: cd integration-tests/ && go test smoke/ccip_messaging_test.go -timeout 12m -test.parallel=1 -count=1 -json + pyroscope_env: ci-smoke-ccipv1_6-evm-simulated + test_env_vars: + E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2 + E2E_JD_VERSION: 0.4.0 # END: CCIPv1.6 tests @@ -1178,4 +1192,4 @@ runner-test-matrix: TEST_LOG_LEVEL: debug E2E_TEST_GRAFANA_DASHBOARD_URL: /d/6vjVx-1V8/ccip-long-running-tests - # END: CCIP tests \ No newline at end of file + # END: CCIP tests diff --git a/deployment/ccip/add_lane_test.go b/deployment/ccip/add_lane_test.go index 223d978b814..02fea79c911 100644 --- a/deployment/ccip/add_lane_test.go +++ b/deployment/ccip/add_lane_test.go @@ -7,6 +7,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" + commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/deployment" @@ -119,7 +120,7 @@ func TestAddLane(t *testing.T) { ExtraArgs: nil, }) require.Equal(t, uint64(1), seqNum2) - require.NoError(t, ConfirmExecWithSeqNr(t, e.Env.Chains[chain2], e.Env.Chains[chain1], state.Chains[chain1].OffRamp, &startBlock2, seqNum2)) + require.NoError(t, commonutils.JustError(ConfirmExecWithSeqNr(t, e.Env.Chains[chain2], e.Env.Chains[chain1], state.Chains[chain1].OffRamp, &startBlock2, seqNum2))) // now check for the previous message from chain 1 to chain 2 that it has not been executed till now as the onRamp was disabled ConfirmNoExecConsistentlyWithSeqNr(t, e.Env.Chains[chain1], e.Env.Chains[chain2], state.Chains[chain2].OffRamp, seqNum1, 30*time.Second) @@ -145,5 +146,5 @@ func TestAddLane(t *testing.T) { ReplayLogs(t, e.Env.Offchain, replayBlocks) time.Sleep(30 * time.Second) // Now that the onRamp is enabled, the request should be processed - require.NoError(t, ConfirmExecWithSeqNr(t, e.Env.Chains[chain1], e.Env.Chains[chain2], state.Chains[chain2].OffRamp, &startBlock, seqNum1)) + require.NoError(t, commonutils.JustError(ConfirmExecWithSeqNr(t, e.Env.Chains[chain1], e.Env.Chains[chain2], state.Chains[chain2].OffRamp, &startBlock, seqNum1))) } diff --git a/deployment/ccip/changeset/add_chain_test.go b/deployment/ccip/changeset/add_chain_test.go index ff02430fd51..6a87bdd0a0a 100644 --- a/deployment/ccip/changeset/add_chain_test.go +++ b/deployment/ccip/changeset/add_chain_test.go @@ -16,6 +16,7 @@ import ( "github.com/stretchr/testify/require" cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" @@ -224,7 +225,7 @@ func TestAddChainInbound(t *testing.T) { cciptypes.SeqNum(seqNr), })) require.NoError(t, - ccipdeployment.ConfirmExecWithSeqNr(t, e.Env.Chains[initialDeploy[0]], e.Env.Chains[newChain], state.Chains[newChain].OffRamp, &startBlock, seqNr)) + commonutils.JustError(ccipdeployment.ConfirmExecWithSeqNr(t, e.Env.Chains[initialDeploy[0]], e.Env.Chains[newChain], state.Chains[newChain].OffRamp, &startBlock, seqNr))) linkAddress := state.Chains[newChain].LinkToken.Address() feeQuoter := state.Chains[newChain].FeeQuoter diff --git a/deployment/ccip/test_assertions.go b/deployment/ccip/test_assertions.go index 373610531a1..64d1eb8571c 100644 --- a/deployment/ccip/test_assertions.go +++ b/deployment/ccip/test_assertions.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math/big" + "sync" "testing" "time" @@ -13,6 +14,7 @@ import ( "golang.org/x/sync/errgroup" "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/deployment" @@ -248,6 +250,26 @@ func ConfirmCommitWithExpectedSeqNumRange( } t.Logf("Waiting for commit report on chain selector %d from source selector %d expected seq nr range %s", dest.Selector, src.Selector, expectedSeqNumRange.String()) + + // Need to do this because the subscription sometimes fails to get the event. + iter, err := offRamp.FilterCommitReportAccepted(&bind.FilterOpts{ + Context: tests.Context(t), + }) + require.NoError(t, err) + for iter.Next() { + event := iter.Event + if len(event.MerkleRoots) > 0 { + for _, mr := range event.MerkleRoots { + if mr.SourceChainSelector == src.Selector && + uint64(expectedSeqNumRange.Start()) >= mr.MinSeqNr && + uint64(expectedSeqNumRange.End()) <= mr.MaxSeqNr { + t.Logf("Received commit report for [%d, %d] on selector %d from source selector %d expected seq nr range %s, token prices: %v", + mr.MinSeqNr, mr.MaxSeqNr, dest.Selector, src.Selector, expectedSeqNumRange.String(), event.PriceUpdates.TokenPriceUpdates) + return nil + } + } + } + } case subErr := <-subscription.Err(): return fmt.Errorf("subscription error: %w", subErr) case <-timer.C: @@ -272,6 +294,7 @@ func ConfirmCommitWithExpectedSeqNumRange( } // ConfirmExecWithSeqNrForAll waits for all chains in the environment to execute the given expectedSeqNums. +// If successful, it returns a map that maps the expected sequence numbers to their respective execution state. // expectedSeqNums is a map of destination chain selector to expected sequence number // startBlocks is a map of destination chain selector to start block number to start watching from. // If startBlocks is nil, it will start watching from the latest block. @@ -281,8 +304,12 @@ func ConfirmExecWithSeqNrForAll( state CCIPOnChainState, expectedSeqNums map[uint64]uint64, startBlocks map[uint64]*uint64, -) { - var wg errgroup.Group +) (executionStates map[uint64]int) { + var ( + wg errgroup.Group + mx sync.Mutex + ) + executionStates = make(map[uint64]int) for src, srcChain := range e.Chains { for dest, dstChain := range e.Chains { if src == dest { @@ -300,7 +327,7 @@ func ConfirmExecWithSeqNrForAll( return nil } - return ConfirmExecWithSeqNr( + executionState, err := ConfirmExecWithSeqNr( t, srcChain, dstChain, @@ -308,10 +335,20 @@ func ConfirmExecWithSeqNrForAll( startBlock, expectedSeqNums[dstChain.Selector], ) + if err != nil { + return err + } + + mx.Lock() + executionStates[expectedSeqNums[dstChain.Selector]] = executionState + mx.Unlock() + + return nil }) } } require.NoError(t, wg.Wait()) + return executionStates } // ConfirmExecWithSeqNr waits for an execution state change on the destination chain with the expected sequence number. @@ -323,7 +360,7 @@ func ConfirmExecWithSeqNr( offRamp *offramp.OffRamp, startBlock *uint64, expectedSeqNr uint64, -) error { +) (executionState int, err error) { timer := time.NewTimer(5 * time.Minute) defer timer.Stop() tick := time.NewTicker(5 * time.Second) @@ -334,7 +371,7 @@ func ConfirmExecWithSeqNr( Start: startBlock, }, sink, nil, nil, nil) if err != nil { - return fmt.Errorf("error to subscribe ExecutionStateChanged : %w", err) + return -1, fmt.Errorf("error to subscribe ExecutionStateChanged : %w", err) } defer subscription.Unsubscribe() for { @@ -346,7 +383,7 @@ func ConfirmExecWithSeqNr( if executionState == EXECUTION_STATE_SUCCESS || executionState == EXECUTION_STATE_FAILURE { t.Logf("Observed %s execution state on chain %d (offramp %s) from chain %d with expected sequence number %d", executionStateToString(executionState), dest.Selector, offRamp.Address().String(), source.Selector, expectedSeqNr) - return nil + return int(executionState), nil } case execEvent := <-sink: t.Logf("Received ExecutionStateChanged (state %s) for seqNum %d on chain %d (offramp %s) from chain %d", @@ -354,13 +391,13 @@ func ConfirmExecWithSeqNr( if execEvent.SequenceNumber == expectedSeqNr && execEvent.SourceChainSelector == source.Selector { t.Logf("Received ExecutionStateChanged (state %s) on chain %d (offramp %s) from chain %d with expected sequence number %d", executionStateToString(execEvent.State), dest.Selector, offRamp.Address().String(), source.Selector, expectedSeqNr) - return nil + return int(execEvent.State), nil } case <-timer.C: - return fmt.Errorf("timed out waiting for ExecutionStateChanged on chain %d (offramp %s) from chain %d with expected sequence number %d", + return -1, fmt.Errorf("timed out waiting for ExecutionStateChanged on chain %d (offramp %s) from chain %d with expected sequence number %d", dest.Selector, offRamp.Address().String(), source.Selector, expectedSeqNr) case subErr := <-subscription.Err(): - return fmt.Errorf("subscription error: %w", subErr) + return -1, fmt.Errorf("subscription error: %w", subErr) } } } diff --git a/deployment/ccip/test_helpers.go b/deployment/ccip/test_helpers.go index f62b8e15c79..cfa637ee9b0 100644 --- a/deployment/ccip/test_helpers.go +++ b/deployment/ccip/test_helpers.go @@ -16,6 +16,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" @@ -287,7 +288,9 @@ func TestSendRequest( return seqNum } -func MakeExtraArgsV2(gasLimit uint64, allowOOO bool) []byte { +// MakeEVMExtraArgsV2 creates the extra args for the EVM2Any message that is destined +// for an EVM chain. The extra args contain the gas limit and allow out of order flag. +func MakeEVMExtraArgsV2(gasLimit uint64, allowOOO bool) []byte { // extra args is the tag followed by the gas limit and allowOOO abi-encoded. var extraArgs []byte extraArgs = append(extraArgs, evmExtraArgsV2Tag...) @@ -454,8 +457,19 @@ func ConfirmRequestOnSourceAndDest(t *testing.T, env deployment.Environment, sta })) fmt.Printf("Commit confirmed for seqnr %d", seqNum) - require.NoError(t, - ConfirmExecWithSeqNr(t, env.Chains[sourceCS], env.Chains[destCS], state.Chains[destCS].OffRamp, &startBlock, seqNum)) + require.NoError( + t, + commonutils.JustError( + ConfirmExecWithSeqNr( + t, + env.Chains[sourceCS], + env.Chains[destCS], + state.Chains[destCS].OffRamp, + &startBlock, + seqNum, + ), + ), + ) return nil } diff --git a/deployment/ccip/changeset/messaging_test.go b/integration-tests/smoke/ccip_messaging_test.go similarity index 71% rename from deployment/ccip/changeset/messaging_test.go rename to integration-tests/smoke/ccip_messaging_test.go index a5fde58742b..55309598c8c 100644 --- a/deployment/ccip/changeset/messaging_test.go +++ b/integration-tests/smoke/ccip_messaging_test.go @@ -1,4 +1,4 @@ -package changeset +package smoke import ( "testing" @@ -6,13 +6,18 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "golang.org/x/exp/maps" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" "github.com/smartcontractkit/chainlink/deployment" + ccdeploy "github.com/smartcontractkit/chainlink/deployment/ccip" ccipdeployment "github.com/smartcontractkit/chainlink/deployment/ccip" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testsetups" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/test-go/testify/require" - "golang.org/x/exp/maps" ) type testCaseSetup struct { @@ -34,12 +39,13 @@ type messagingTestCaseOutput struct { nonce uint64 } -func Test_Messaging(t *testing.T) { - t.Parallel() - +func Test_CCIPMessaging(t *testing.T) { // Setup 2 chains and a single lane. - e := ccipdeployment.NewMemoryEnvironmentWithJobs(t, logger.TestLogger(t), 2, 4) - state, err := ccipdeployment.LoadOnchainState(e.Env) + lggr := logger.TestLogger(t) + ctx := ccdeploy.Context(t) + e, _, _ := testsetups.NewLocalDevEnvironment(t, lggr) + + state, err := ccdeploy.LoadOnchainState(e.Env) require.NoError(t, err) allChainSelectors := maps.Keys(e.Env.Chains) @@ -54,20 +60,37 @@ func Test_Messaging(t *testing.T) { ) tokenConfig := ccipdeployment.NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds) - newAddresses := deployment.NewMemoryAddressBook() - err = ccipdeployment.DeployCCIPContracts(e.Env, newAddresses, ccipdeployment.DeployCCIPContractConfig{ + // Apply migration + output, err := changeset.InitialDeploy(e.Env, ccdeploy.DeployCCIPContractConfig{ HomeChainSel: e.HomeChainSel, FeedChainSel: e.FeedChainSel, ChainsToDeploy: allChainSelectors, TokenConfig: tokenConfig, - MCMSConfig: ccipdeployment.NewTestMCMSConfig(t, e.Env), + MCMSConfig: ccdeploy.NewTestMCMSConfig(t, e.Env), OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), }) require.NoError(t, err) - require.NoError(t, e.Env.ExistingAddresses.Merge(newAddresses)) - state, err = ccipdeployment.LoadOnchainState(e.Env) + require.NoError(t, e.Env.ExistingAddresses.Merge(output.AddressBook)) + // Get new state after migration. + state, err = ccdeploy.LoadOnchainState(e.Env) require.NoError(t, err) + // Ensure capreg logs are up to date. + ccdeploy.ReplayLogs(t, e.Env.Offchain, e.ReplayBlocks) + + // Apply the jobs. + for nodeID, jobs := range output.JobSpecs { + for _, job := range jobs { + // Note these auto-accept + _, err := e.Env.Offchain.ProposeJob(ctx, + &jobv1.ProposeJobRequest{ + NodeId: nodeID, + Spec: job, + }) + require.NoError(t, err) + } + } + // connect a single lane, source to dest require.NoError(t, ccipdeployment.AddLane(e.Env, state, sourceChain, destChain)) @@ -94,6 +117,8 @@ func Test_Messaging(t *testing.T) { }, common.HexToAddress("0xdead"), []byte("hello eoa"), + nil, // default extraArgs + ccipdeployment.EXECUTION_STATE_SUCCESS, // success because offRamp won't call an EOA ) }) @@ -106,6 +131,8 @@ func Test_Messaging(t *testing.T) { }, state.Chains[destChain].FeeQuoter.Address(), []byte("hello FeeQuoter"), + nil, // default extraArgs + ccipdeployment.EXECUTION_STATE_SUCCESS, // success because offRamp won't call a contract not implementing CCIPReceiver ) }) @@ -118,6 +145,8 @@ func Test_Messaging(t *testing.T) { }, state.Chains[destChain].Receiver.Address(), []byte("hello CCIPReceiver"), + nil, // default extraArgs + ccipdeployment.EXECUTION_STATE_SUCCESS, func(t *testing.T) { iter, err := state.Chains[destChain].Receiver.FilterMessageReceived(nil) require.NoError(t, err) @@ -136,17 +165,8 @@ func Test_Messaging(t *testing.T) { }, state.Chains[destChain].Receiver.Address(), []byte("hello CCIPReceiver with low exec gas"), - func(t *testing.T) { - // Message should not be emitted, not enough gas to emit log. - // TODO: this is still returning a log, probably the older one since FAILURE is the execution state. - // Not enough ctx in the message received log to confirm that it's from another test. - // Maybe check the log block number and assert that its < the header before block number from above? - // iter, err := ccipReceiver.FilterMessageReceived(&bind.FilterOpts{ - // Start: headerBefore.Number.Uint64(), - // }) - // require.NoError(t, err) - // require.False(t, iter.Next(), "MessageReceived should not be emitted in this test case since gas is too low") - }, + ccipdeployment.MakeEVMExtraArgsV2(1, false), // 1 gas is too low. + ccipdeployment.EXECUTION_STATE_FAILURE, // state would be failed onchain due to low gas ) }) } @@ -163,6 +183,8 @@ func runMessagingTestCase( tc messagingTestCase, receiver common.Address, msgData []byte, + extraArgs []byte, + expectedExecutionState int, extraAssertions ...func(t *testing.T), ) (out messagingTestCaseOutput) { // check latest nonce @@ -178,7 +200,7 @@ func runMessagingTestCase( Data: msgData, TokenAmounts: nil, FeeToken: common.HexToAddress("0x0"), - ExtraArgs: nil, + ExtraArgs: extraArgs, }) expectedSeqNum := make(map[uint64]uint64) expectedSeqNum[tc.destChain] = seqNum @@ -190,7 +212,17 @@ func runMessagingTestCase( } ccipdeployment.ConfirmCommitForAllWithExpectedSeqNums(tc.t, tc.deployedEnv.Env, tc.onchainState, expectedSeqNum, startBlocks) - ccipdeployment.ConfirmExecWithSeqNrForAll(tc.t, tc.deployedEnv.Env, tc.onchainState, expectedSeqNum, startBlocks) + execStates := ccipdeployment.ConfirmExecWithSeqNrForAll(tc.t, tc.deployedEnv.Env, tc.onchainState, expectedSeqNum, startBlocks) + + require.Equalf( + tc.t, + expectedExecutionState, + execStates[seqNum], + "wrong execution state for seq nr %d, expected %d, got %d", + seqNum, + expectedExecutionState, + execStates[seqNum], + ) // check the sender latestNonce on the dest, should be incremented latestNonce, err = tc.onchainState.Chains[tc.destChain].NonceManager.GetInboundNonce(&bind.CallOpts{ From a25ab3dc21043b191875c368460820121561eb1c Mon Sep 17 00:00:00 2001 From: Christian Edward Jackson-Gruber Date: Wed, 13 Nov 2024 09:23:13 -0800 Subject: [PATCH 09/14] Move Changeset to use a generic type for the config, to avoid a bunch of boilerplate casting. (#15195) * Move Changeset to use a generic type for the config, to avoid a lot of reflection and casting * Update deployment/keystone/changeset/append_node_capbilities.go Co-authored-by: Jordan Krage * Fix caller * Revert collapsing of pointers here, to reduce impact on calling code. --------- Co-authored-by: Jordan Krage --- deployment/ccip/changeset/home_chain.go | 9 +++------ deployment/ccip/changeset/initial_deploy.go | 8 ++------ deployment/changeset.go | 2 +- deployment/keystone/changeset/append_node_capbilities.go | 9 ++------- deployment/keystone/changeset/deploy_forwarder.go | 8 ++------ deployment/keystone/changeset/update_don.go | 5 ++--- .../keystone/changeset/update_node_capabilities.go | 9 +++------ 7 files changed, 15 insertions(+), 35 deletions(-) diff --git a/deployment/ccip/changeset/home_chain.go b/deployment/ccip/changeset/home_chain.go index 5fa5cab5b21..7d7f64a8bb8 100644 --- a/deployment/ccip/changeset/home_chain.go +++ b/deployment/ccip/changeset/home_chain.go @@ -13,14 +13,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" ) -var _ deployment.ChangeSet = DeployHomeChain +var _ deployment.ChangeSet[DeployHomeChainConfig] = DeployHomeChain // DeployHomeChain is a separate changeset because it is a standalone deployment performed once in home chain for the entire CCIP deployment. -func DeployHomeChain(env deployment.Environment, config interface{}) (deployment.ChangesetOutput, error) { - cfg, ok := config.(DeployHomeChainConfig) - if !ok { - return deployment.ChangesetOutput{}, deployment.ErrInvalidConfig - } +func DeployHomeChain(env deployment.Environment, cfg DeployHomeChainConfig) (deployment.ChangesetOutput, error) { + err := cfg.Validate() if err != nil { return deployment.ChangesetOutput{}, errors.Wrapf(deployment.ErrInvalidConfig, "%v", err) diff --git a/deployment/ccip/changeset/initial_deploy.go b/deployment/ccip/changeset/initial_deploy.go index f9d7caf44a3..de17834e8bd 100644 --- a/deployment/ccip/changeset/initial_deploy.go +++ b/deployment/ccip/changeset/initial_deploy.go @@ -8,13 +8,9 @@ import ( ccipdeployment "github.com/smartcontractkit/chainlink/deployment/ccip" ) -var _ deployment.ChangeSet = InitialDeploy +var _ deployment.ChangeSet[ccipdeployment.DeployCCIPContractConfig] = InitialDeploy -func InitialDeploy(env deployment.Environment, config interface{}) (deployment.ChangesetOutput, error) { - c, ok := config.(ccipdeployment.DeployCCIPContractConfig) - if !ok { - return deployment.ChangesetOutput{}, deployment.ErrInvalidConfig - } +func InitialDeploy(env deployment.Environment, c ccipdeployment.DeployCCIPContractConfig) (deployment.ChangesetOutput, error) { newAddresses := deployment.NewMemoryAddressBook() err := ccipdeployment.DeployCCIPContracts(env, newAddresses, c) if err != nil { diff --git a/deployment/changeset.go b/deployment/changeset.go index e6c0988e67e..abce4942203 100644 --- a/deployment/changeset.go +++ b/deployment/changeset.go @@ -18,7 +18,7 @@ var ( // Its recommended that changesets operate on a small number of chains (e.g. 1-3) // to reduce the risk of partial failures. // If the configuration is unexpected type or format, the changeset should return ErrInvalidConfig. -type ChangeSet func(e Environment, config interface{}) (ChangesetOutput, error) +type ChangeSet[C any] func(e Environment, config C) (ChangesetOutput, error) // ChangesetOutput is the output of a Changeset function. // Think of it like a state transition output. diff --git a/deployment/keystone/changeset/append_node_capbilities.go b/deployment/keystone/changeset/append_node_capbilities.go index ae654b7017d..974c4970c51 100644 --- a/deployment/keystone/changeset/append_node_capbilities.go +++ b/deployment/keystone/changeset/append_node_capbilities.go @@ -8,19 +8,14 @@ import ( "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" ) -var _ deployment.ChangeSet = AppendNodeCapabilities +var _ deployment.ChangeSet[*AppendNodeCapabilitiesRequest] = AppendNodeCapabilities // AppendNodeCapabilitiesRequest is a request to add capabilities to the existing capabilities of nodes in the registry type AppendNodeCapabilitiesRequest = MutateNodeCapabilitiesRequest // AppendNodeCapabilities adds any new capabilities to the registry, merges the new capabilities with the existing capabilities // of the node, and updates the nodes in the registry host the union of the new and existing capabilities. -func AppendNodeCapabilities(env deployment.Environment, config any) (deployment.ChangesetOutput, error) { - req, ok := config.(*AppendNodeCapabilitiesRequest) - if !ok { - return deployment.ChangesetOutput{}, fmt.Errorf("invalid config type") - } - +func AppendNodeCapabilities(env deployment.Environment, req *AppendNodeCapabilitiesRequest) (deployment.ChangesetOutput, error) { cfg, err := req.convert(env) if err != nil { return deployment.ChangesetOutput{}, err diff --git a/deployment/keystone/changeset/deploy_forwarder.go b/deployment/keystone/changeset/deploy_forwarder.go index d6adbee0252..55ab0dcd86d 100644 --- a/deployment/keystone/changeset/deploy_forwarder.go +++ b/deployment/keystone/changeset/deploy_forwarder.go @@ -7,13 +7,9 @@ import ( kslib "github.com/smartcontractkit/chainlink/deployment/keystone" ) -var _ deployment.ChangeSet = DeployForwarder +var _ deployment.ChangeSet[uint64] = DeployForwarder -func DeployForwarder(env deployment.Environment, config interface{}) (deployment.ChangesetOutput, error) { - registryChainSel, ok := config.(uint64) - if !ok { - return deployment.ChangesetOutput{}, deployment.ErrInvalidConfig - } +func DeployForwarder(env deployment.Environment, registryChainSel uint64) (deployment.ChangesetOutput, error) { lggr := env.Logger // expect OCR3 to be deployed & capabilities registry regAddrs, err := env.ExistingAddresses.AddressesForChain(registryChainSel) diff --git a/deployment/keystone/changeset/update_don.go b/deployment/keystone/changeset/update_don.go index 1a535c5aa11..1ab40d5a935 100644 --- a/deployment/keystone/changeset/update_don.go +++ b/deployment/keystone/changeset/update_don.go @@ -8,7 +8,7 @@ import ( kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" ) -var _ deployment.ChangeSet = UpdateDon +var _ deployment.ChangeSet[*UpdateDonRequest] = UpdateDon // CapabilityConfig is a struct that holds a capability and its configuration type CapabilityConfig = internal.CapabilityConfig @@ -22,8 +22,7 @@ type UpdateDonResponse struct { // UpdateDon updates the capabilities of a Don // This a complex action in practice that involves registering missing capabilities, adding the nodes, and updating // the capabilities of the DON -func UpdateDon(env deployment.Environment, cfg any) (deployment.ChangesetOutput, error) { - req := cfg.(*UpdateDonRequest) +func UpdateDon(env deployment.Environment, req *UpdateDonRequest) (deployment.ChangesetOutput, error) { _, err := internal.UpdateDon(env.Logger, req) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to update don: %w", err) diff --git a/deployment/keystone/changeset/update_node_capabilities.go b/deployment/keystone/changeset/update_node_capabilities.go index 09cf351cc85..1d590d02831 100644 --- a/deployment/keystone/changeset/update_node_capabilities.go +++ b/deployment/keystone/changeset/update_node_capabilities.go @@ -5,6 +5,7 @@ import ( "fmt" chainsel "github.com/smartcontractkit/chain-selectors" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" kslib "github.com/smartcontractkit/chainlink/deployment/keystone" @@ -14,7 +15,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" ) -var _ deployment.ChangeSet = UpdateNodeCapabilities +var _ deployment.ChangeSet[*MutateNodeCapabilitiesRequest] = UpdateNodeCapabilities type P2PSignerEnc = internal.P2PSignerEnc @@ -84,11 +85,7 @@ func (req *MutateNodeCapabilitiesRequest) updateNodeCapabilitiesImplRequest(e de } // UpdateNodeCapabilities updates the capabilities of nodes in the registry -func UpdateNodeCapabilities(env deployment.Environment, config any) (deployment.ChangesetOutput, error) { - req, ok := config.(*MutateNodeCapabilitiesRequest) - if !ok { - return deployment.ChangesetOutput{}, fmt.Errorf("invalid config type. want %T, got %T", &MutateNodeCapabilitiesRequest{}, config) - } +func UpdateNodeCapabilities(env deployment.Environment, req *MutateNodeCapabilitiesRequest) (deployment.ChangesetOutput, error) { c, err := req.updateNodeCapabilitiesImplRequest(env) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to convert request: %w", err) From 5663e1bbf28c9be2783e309188e99ca8a84e421b Mon Sep 17 00:00:00 2001 From: Vyzaldy Sanchez Date: Wed, 13 Nov 2024 13:27:38 -0400 Subject: [PATCH 10/14] Log failed transactions into beholder (#15187) * Logs failed transactions into beholder * Adds log when failing to `GetTransactionStatus` * Fixes tests * Sets emit labels * Logs unexpected transaction statuses --- core/capabilities/targets/write_target.go | 46 ++++++++++++++++++- .../capabilities/targets/write_target_test.go | 1 + core/services/relay/evm/write_target_test.go | 3 ++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/core/capabilities/targets/write_target.go b/core/capabilities/targets/write_target.go index 0e0b2071829..9315a1ee199 100644 --- a/core/capabilities/targets/write_target.go +++ b/core/capabilities/targets/write_target.go @@ -7,21 +7,27 @@ import ( "encoding/hex" "fmt" "math/big" + "time" "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/capabilities/consensus/ocr3/types" + "github.com/smartcontractkit/chainlink-common/pkg/custmsg" "github.com/smartcontractkit/chainlink-common/pkg/logger" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" + + "github.com/smartcontractkit/chainlink/v2/core/platform" ) var ( _ capabilities.TargetCapability = &WriteTarget{} ) +const transactionStatusCheckInterval = 2 * time.Second + type WriteTarget struct { cr ContractValueGetter cw commontypes.ChainWriter @@ -31,7 +37,8 @@ type WriteTarget struct { receiverGasMinimum uint64 capabilities.CapabilityInfo - lggr logger.Logger + emitter custmsg.MessageEmitter + lggr logger.Logger bound bool } @@ -79,6 +86,7 @@ func NewWriteTarget( forwarderAddress, txGasLimit - ForwarderContractLogicGasCost, info, + custmsg.NewLabeler(), logger.Named(lggr, "WriteTarget"), false, } @@ -309,7 +317,41 @@ func (cap *WriteTarget) Execute(ctx context.Context, rawRequest capabilities.Cap } cap.lggr.Debugw("Transaction submitted", "request", request, "transaction", txID) - return capabilities.CapabilityResponse{}, nil + + tick := time.NewTicker(transactionStatusCheckInterval) + defer tick.Stop() + for { + select { + case <-ctx.Done(): + return capabilities.CapabilityResponse{}, nil + case <-tick.C: + txStatus, err := cap.cw.GetTransactionStatus(ctx, txID.String()) + if err != nil { + cap.lggr.Errorw("Failed to get transaction status", "request", request, "transaction", txID, "err", err) + continue + } + switch txStatus { + case commontypes.Finalized: + cap.lggr.Debugw("Transaction finalized", "request", request, "transaction", txID) + return capabilities.CapabilityResponse{}, nil + case commontypes.Failed, commontypes.Fatal: + cap.lggr.Error("Transaction failed", "request", request, "transaction", txID) + msg := "failed to submit transaction with ID: " + txID.String() + err = cap.emitter.With( + platform.KeyWorkflowID, request.Metadata.WorkflowID, + platform.KeyWorkflowName, request.Metadata.WorkflowName, + platform.KeyWorkflowOwner, request.Metadata.WorkflowOwner, + platform.KeyWorkflowExecutionID, request.Metadata.WorkflowExecutionID, + ).Emit(ctx, msg) + if err != nil { + cap.lggr.Errorf("failed to send custom message with msg: %s, err: %v", msg, err) + } + return capabilities.CapabilityResponse{}, fmt.Errorf("submitted transaction failed: %w", err) + default: + cap.lggr.Debugw("Unexpected transaction status", "request", request, "transaction", txID, "status", txStatus) + } + } + } } func (cap *WriteTarget) RegisterToWorkflow(ctx context.Context, request capabilities.RegisterToWorkflowRequest) error { diff --git a/core/capabilities/targets/write_target_test.go b/core/capabilities/targets/write_target_test.go index 499f4f9b29b..38136f07df0 100644 --- a/core/capabilities/targets/write_target_test.go +++ b/core/capabilities/targets/write_target_test.go @@ -101,6 +101,7 @@ func TestWriteTarget(t *testing.T) { Config: config, Inputs: validInputs, } + cw.On("GetTransactionStatus", mock.Anything, mock.Anything).Return(types.Finalized, nil).Once() response, err2 := writeTarget.Execute(ctx, req) require.NoError(t, err2) diff --git a/core/services/relay/evm/write_target_test.go b/core/services/relay/evm/write_target_test.go index ce169554768..24d7dd8646e 100644 --- a/core/services/relay/evm/write_target_test.go +++ b/core/services/relay/evm/write_target_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + commonTypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/values" "github.com/smartcontractkit/chainlink/v2/common/headtracker/mocks" @@ -110,6 +111,8 @@ func TestEvmWrite(t *testing.T) { evmClient.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(mockCall, nil).Maybe() evmClient.On("CodeAt", mock.Anything, mock.Anything, mock.Anything).Return([]byte("test"), nil) + txManager.On("GetTransactionStatus", mock.Anything, mock.Anything).Return(commonTypes.Finalized, nil) + chain.On("ID").Return(big.NewInt(11155111)) chain.On("TxManager").Return(txManager) chain.On("LogPoller").Return(poller) From cf7db164832ea95354a3c953126c2fd32a59afd7 Mon Sep 17 00:00:00 2001 From: amit-momin <108959691+amit-momin@users.noreply.github.com> Date: Wed, 13 Nov 2024 11:30:27 -0600 Subject: [PATCH 11/14] Updated Solana TXM in-memory storage to track transactions by statuses (#15104) * Updated Solana TXM in-memory storage to track transactions by statuses * Regenerated config doc * Updated chainlink-solana commit * Cleaned up go.sum * Updated chainlink-solana pin * Updated chainlink-solana commit --- .changeset/forty-foxes-watch.md | 5 +++++ core/config/docs/chains-solana.toml | 2 ++ core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- core/services/chainlink/config_test.go | 2 ++ core/services/chainlink/testdata/config-full.toml | 1 + .../chainlink/testdata/config-multi-chain-effective.toml | 2 ++ core/web/resolver/testdata/config-full.toml | 1 + .../resolver/testdata/config-multi-chain-effective.toml | 2 ++ core/web/solana_chains_controller_test.go | 1 + deployment/go.mod | 2 +- deployment/go.sum | 4 ++-- docs/CONFIG.md | 7 +++++++ go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 ++-- 19 files changed, 38 insertions(+), 15 deletions(-) create mode 100644 .changeset/forty-foxes-watch.md diff --git a/.changeset/forty-foxes-watch.md b/.changeset/forty-foxes-watch.md new file mode 100644 index 00000000000..cb118d50021 --- /dev/null +++ b/.changeset/forty-foxes-watch.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +Updated Solana TXM's in-memory storage to track statuses across the Solana transaction lifecycle. Added a method to translate Solana transaction statuses into states expected by the ChainWriter interface. Made the duration transactions are retained in storage after finality or error configurable using `TxRetentionTimeout`. #added diff --git a/core/config/docs/chains-solana.toml b/core/config/docs/chains-solana.toml index 87d71b49cc6..c979581b258 100644 --- a/core/config/docs/chains-solana.toml +++ b/core/config/docs/chains-solana.toml @@ -17,6 +17,8 @@ TxTimeout = '1m' # Default TxRetryTimeout = '10s' # Default # TxConfirmTimeout is the duration to wait when confirming a tx signature, before discarding as unconfirmed. TxConfirmTimeout = '30s' # Default +# TxRetentionTimeout is the duration to retain transactions in storage after being marked as finalized or errored. Set to 0 to immediately drop transactions. +TxRetentionTimeout = '0s' # Default # SkipPreflight enables or disables preflight checks when sending txs. SkipPreflight = true # Default # Commitment is the confirmation level for solana state and transactions. ([documentation](https://docs.solana.com/developing/clients/jsonrpc-api#configuring-state-commitment)) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 6de43b49e55..a8367d0d4d9 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -300,7 +300,7 @@ require ( github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 // indirect - github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 // indirect + github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112213949-65ae13752669 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 // indirect github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 3a7f6db8076..4919877a650 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1106,8 +1106,8 @@ github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 h1:1xTm8UGeD github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 h1:PBUaFfPLm+Efq7H9kdfGBivH+QhJ6vB5EZTR/sCZsxI= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 h1:blu++xbH/NSb+ii5hI4jczwojZ7Hc1ERXjpt/krYy9c= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930/go.mod h1:mGmRvlk54ufCufV4EBWizOGtXoXfePoFAuYEVC8EwdY= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112213949-65ae13752669 h1:CBQ9ORUtGUvCr3dAm/qjpdHlYuB1SRIwtYw5LV8SLys= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112213949-65ae13752669/go.mod h1:mGmRvlk54ufCufV4EBWizOGtXoXfePoFAuYEVC8EwdY= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 h1:B4DFdk6MGcQnoCjjMBCx7Z+GWQpxRWJ4O8W/dVJyWGA= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8/go.mod h1:WkBqgBo+g34Gm5vWkDDl8Fh3Mzd7bF5hXp7rryg0t5o= github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12ijqMM9tvYVEm+nR826WsrNi6zCKpwBhuApq127wHs= diff --git a/core/services/chainlink/config_test.go b/core/services/chainlink/config_test.go index 10a861960ac..76b80672dbb 100644 --- a/core/services/chainlink/config_test.go +++ b/core/services/chainlink/config_test.go @@ -745,6 +745,7 @@ func TestConfig_Marshal(t *testing.T) { TxTimeout: commoncfg.MustNewDuration(time.Hour), TxRetryTimeout: commoncfg.MustNewDuration(time.Minute), TxConfirmTimeout: commoncfg.MustNewDuration(time.Second), + TxRetentionTimeout: commoncfg.MustNewDuration(0 * time.Second), SkipPreflight: ptr(true), Commitment: ptr("banana"), MaxRetries: ptr[int64](7), @@ -1272,6 +1273,7 @@ OCR2CacheTTL = '1h0m0s' TxTimeout = '1h0m0s' TxRetryTimeout = '1m0s' TxConfirmTimeout = '1s' +TxRetentionTimeout = '0s' SkipPreflight = true Commitment = 'banana' MaxRetries = 7 diff --git a/core/services/chainlink/testdata/config-full.toml b/core/services/chainlink/testdata/config-full.toml index c5d79dbe5bc..c6a5302a459 100644 --- a/core/services/chainlink/testdata/config-full.toml +++ b/core/services/chainlink/testdata/config-full.toml @@ -492,6 +492,7 @@ OCR2CacheTTL = '1h0m0s' TxTimeout = '1h0m0s' TxRetryTimeout = '1m0s' TxConfirmTimeout = '1s' +TxRetentionTimeout = '0s' SkipPreflight = true Commitment = 'banana' MaxRetries = 7 diff --git a/core/services/chainlink/testdata/config-multi-chain-effective.toml b/core/services/chainlink/testdata/config-multi-chain-effective.toml index d71ebc4a2d5..e8da8142181 100644 --- a/core/services/chainlink/testdata/config-multi-chain-effective.toml +++ b/core/services/chainlink/testdata/config-multi-chain-effective.toml @@ -653,6 +653,7 @@ OCR2CacheTTL = '1m0s' TxTimeout = '1m0s' TxRetryTimeout = '10s' TxConfirmTimeout = '30s' +TxRetentionTimeout = '0s' SkipPreflight = true Commitment = 'confirmed' MaxRetries = 12 @@ -697,6 +698,7 @@ OCR2CacheTTL = '1m0s' TxTimeout = '1m0s' TxRetryTimeout = '10s' TxConfirmTimeout = '30s' +TxRetentionTimeout = '0s' SkipPreflight = true Commitment = 'confirmed' MaxRetries = 0 diff --git a/core/web/resolver/testdata/config-full.toml b/core/web/resolver/testdata/config-full.toml index 3ae24d81f40..bfb0dcb9961 100644 --- a/core/web/resolver/testdata/config-full.toml +++ b/core/web/resolver/testdata/config-full.toml @@ -491,6 +491,7 @@ OCR2CacheTTL = '1h0m0s' TxTimeout = '1h0m0s' TxRetryTimeout = '1m0s' TxConfirmTimeout = '1s' +TxRetentionTimeout = '0s' SkipPreflight = true Commitment = 'banana' MaxRetries = 7 diff --git a/core/web/resolver/testdata/config-multi-chain-effective.toml b/core/web/resolver/testdata/config-multi-chain-effective.toml index ea8022fa6ae..074cb82482b 100644 --- a/core/web/resolver/testdata/config-multi-chain-effective.toml +++ b/core/web/resolver/testdata/config-multi-chain-effective.toml @@ -653,6 +653,7 @@ OCR2CacheTTL = '1m0s' TxTimeout = '1m0s' TxRetryTimeout = '10s' TxConfirmTimeout = '30s' +TxRetentionTimeout = '0s' SkipPreflight = true Commitment = 'confirmed' MaxRetries = 12 @@ -697,6 +698,7 @@ OCR2CacheTTL = '1m0s' TxTimeout = '1m0s' TxRetryTimeout = '10s' TxConfirmTimeout = '30s' +TxRetentionTimeout = '0s' SkipPreflight = true Commitment = 'confirmed' MaxRetries = 0 diff --git a/core/web/solana_chains_controller_test.go b/core/web/solana_chains_controller_test.go index 56605f734aa..4aa0dbe579d 100644 --- a/core/web/solana_chains_controller_test.go +++ b/core/web/solana_chains_controller_test.go @@ -49,6 +49,7 @@ OCR2CacheTTL = '1m0s' TxTimeout = '1h0m0s' TxRetryTimeout = '10s' TxConfirmTimeout = '30s' +TxRetentionTimeout = '0s' SkipPreflight = false Commitment = 'confirmed' MaxRetries = 0 diff --git a/deployment/go.mod b/deployment/go.mod index c9da65fd6c6..3ca839c88a0 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -405,7 +405,7 @@ require ( github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 // indirect - github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 // indirect + github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112213949-65ae13752669 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 // indirect github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0 // indirect github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.5 // indirect diff --git a/deployment/go.sum b/deployment/go.sum index 38bcb4b96a1..6cf64ab085a 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1396,8 +1396,8 @@ github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 h1:1xTm8UGeD github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 h1:PBUaFfPLm+Efq7H9kdfGBivH+QhJ6vB5EZTR/sCZsxI= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 h1:blu++xbH/NSb+ii5hI4jczwojZ7Hc1ERXjpt/krYy9c= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930/go.mod h1:mGmRvlk54ufCufV4EBWizOGtXoXfePoFAuYEVC8EwdY= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112213949-65ae13752669 h1:CBQ9ORUtGUvCr3dAm/qjpdHlYuB1SRIwtYw5LV8SLys= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112213949-65ae13752669/go.mod h1:mGmRvlk54ufCufV4EBWizOGtXoXfePoFAuYEVC8EwdY= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 h1:B4DFdk6MGcQnoCjjMBCx7Z+GWQpxRWJ4O8W/dVJyWGA= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8/go.mod h1:WkBqgBo+g34Gm5vWkDDl8Fh3Mzd7bF5hXp7rryg0t5o= github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 h1:T0kbw07Vb6xUyA9MIJZfErMgWseWi1zf7cYvRpoq7ug= diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 7d4c34e7531..47ba5b574cd 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -10079,6 +10079,7 @@ OCR2CacheTTL = '1m' # Default TxTimeout = '1m' # Default TxRetryTimeout = '10s' # Default TxConfirmTimeout = '30s' # Default +TxRetentionTimeout = '0s' # Default SkipPreflight = true # Default Commitment = 'confirmed' # Default MaxRetries = 0 # Default @@ -10148,6 +10149,12 @@ TxConfirmTimeout = '30s' # Default ``` TxConfirmTimeout is the duration to wait when confirming a tx signature, before discarding as unconfirmed. +### TxRetentionTimeout +```toml +TxRetentionTimeout = '0s' # Default +``` +TxRetentionTimeout is the duration to retain transactions in storage after being marked as finalized or errored. Set to 0 to immediately drop transactions. + ### SkipPreflight ```toml SkipPreflight = true # Default diff --git a/go.mod b/go.mod index c96444a4260..e2713001ca0 100644 --- a/go.mod +++ b/go.mod @@ -82,7 +82,7 @@ require ( github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e github.com/smartcontractkit/chainlink-feeds v0.1.1 github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 - github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 + github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112213949-65ae13752669 github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 github.com/smartcontractkit/libocr v0.0.0-20241007185508-adbe57025f12 github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de diff --git a/go.sum b/go.sum index c927d19fcfb..1b03627496b 100644 --- a/go.sum +++ b/go.sum @@ -1088,8 +1088,8 @@ github.com/smartcontractkit/chainlink-feeds v0.1.1 h1:JzvUOM/OgGQA1sOqTXXl52R6An github.com/smartcontractkit/chainlink-feeds v0.1.1/go.mod h1:55EZ94HlKCfAsUiKUTNI7QlE/3d3IwTlsU3YNa/nBb4= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 h1:PBUaFfPLm+Efq7H9kdfGBivH+QhJ6vB5EZTR/sCZsxI= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 h1:blu++xbH/NSb+ii5hI4jczwojZ7Hc1ERXjpt/krYy9c= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930/go.mod h1:mGmRvlk54ufCufV4EBWizOGtXoXfePoFAuYEVC8EwdY= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112213949-65ae13752669 h1:CBQ9ORUtGUvCr3dAm/qjpdHlYuB1SRIwtYw5LV8SLys= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112213949-65ae13752669/go.mod h1:mGmRvlk54ufCufV4EBWizOGtXoXfePoFAuYEVC8EwdY= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 h1:B4DFdk6MGcQnoCjjMBCx7Z+GWQpxRWJ4O8W/dVJyWGA= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8/go.mod h1:WkBqgBo+g34Gm5vWkDDl8Fh3Mzd7bF5hXp7rryg0t5o= github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12ijqMM9tvYVEm+nR826WsrNi6zCKpwBhuApq127wHs= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 1d5211adfe4..32a7e666109 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -418,7 +418,7 @@ require ( github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 // indirect - github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 // indirect + github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112213949-65ae13752669 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 // indirect github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 682f4bd70f8..31c4e6c41a6 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1417,8 +1417,8 @@ github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 h1:1xTm8UGeD github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 h1:PBUaFfPLm+Efq7H9kdfGBivH+QhJ6vB5EZTR/sCZsxI= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 h1:blu++xbH/NSb+ii5hI4jczwojZ7Hc1ERXjpt/krYy9c= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930/go.mod h1:mGmRvlk54ufCufV4EBWizOGtXoXfePoFAuYEVC8EwdY= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112213949-65ae13752669 h1:CBQ9ORUtGUvCr3dAm/qjpdHlYuB1SRIwtYw5LV8SLys= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112213949-65ae13752669/go.mod h1:mGmRvlk54ufCufV4EBWizOGtXoXfePoFAuYEVC8EwdY= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 h1:B4DFdk6MGcQnoCjjMBCx7Z+GWQpxRWJ4O8W/dVJyWGA= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8/go.mod h1:WkBqgBo+g34Gm5vWkDDl8Fh3Mzd7bF5hXp7rryg0t5o= github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.2 h1:GDGrC5OGiV0RyM1znYWehSQXyZQWTOzrEeJRYmysPCE= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 780b2daf4a6..870615462a4 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -425,7 +425,7 @@ require ( github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 // indirect - github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 // indirect + github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112213949-65ae13752669 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 // indirect github.com/smartcontractkit/chainlink-testing-framework/lib/grafana v1.50.0 // indirect github.com/smartcontractkit/libocr v0.0.0-20241007185508-adbe57025f12 // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 3d849414c2c..57d80e527cc 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1404,8 +1404,8 @@ github.com/smartcontractkit/chainlink-feeds v0.1.1 h1:JzvUOM/OgGQA1sOqTXXl52R6An github.com/smartcontractkit/chainlink-feeds v0.1.1/go.mod h1:55EZ94HlKCfAsUiKUTNI7QlE/3d3IwTlsU3YNa/nBb4= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0 h1:PBUaFfPLm+Efq7H9kdfGBivH+QhJ6vB5EZTR/sCZsxI= github.com/smartcontractkit/chainlink-protos/orchestrator v0.3.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930 h1:blu++xbH/NSb+ii5hI4jczwojZ7Hc1ERXjpt/krYy9c= -github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112145241-efd6780f6930/go.mod h1:mGmRvlk54ufCufV4EBWizOGtXoXfePoFAuYEVC8EwdY= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112213949-65ae13752669 h1:CBQ9ORUtGUvCr3dAm/qjpdHlYuB1SRIwtYw5LV8SLys= +github.com/smartcontractkit/chainlink-solana v1.1.1-0.20241112213949-65ae13752669/go.mod h1:mGmRvlk54ufCufV4EBWizOGtXoXfePoFAuYEVC8EwdY= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8 h1:B4DFdk6MGcQnoCjjMBCx7Z+GWQpxRWJ4O8W/dVJyWGA= github.com/smartcontractkit/chainlink-starknet/relayer v0.1.1-0.20241017135645-176a23722fd8/go.mod h1:WkBqgBo+g34Gm5vWkDDl8Fh3Mzd7bF5hXp7rryg0t5o= github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.2 h1:GDGrC5OGiV0RyM1znYWehSQXyZQWTOzrEeJRYmysPCE= From 973adb5033443aa15f6a58b83f94b862730fe0a4 Mon Sep 17 00:00:00 2001 From: Matthew Pendrey Date: Wed, 13 Nov 2024 17:31:17 +0000 Subject: [PATCH 12/14] chainreader get latest value with head data (#15188) * chainreader get latest value with head data * revert timeout changes * Fix GetLatestValueWithHeadData * common bump * test/lint fix * lint * common bump * test fix * test fix --------- Co-authored-by: ilija --- core/chains/evm/types/models.go | 19 ++++++++ core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- core/services/relay/evm/chain_reader.go | 34 +++++++++++++- core/services/relay/evm/read/bindings.go | 2 +- core/services/relay/evm/read/bindings_test.go | 15 +++--- core/services/relay/evm/read/event.go | 28 ++++++----- core/services/relay/evm/read/method.go | 47 ++++++++++--------- core/services/relay/evm/read/mocks/reader.go | 44 ++++++++++------- deployment/go.mod | 2 +- deployment/go.sum | 4 +- go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 +- 17 files changed, 147 insertions(+), 72 deletions(-) diff --git a/core/chains/evm/types/models.go b/core/chains/evm/types/models.go index abee992539d..d4dabc96992 100644 --- a/core/chains/evm/types/models.go +++ b/core/chains/evm/types/models.go @@ -8,6 +8,7 @@ import ( "fmt" "math/big" "regexp" + "strconv" "strings" "sync/atomic" "time" @@ -18,10 +19,12 @@ import ( pkgerrors "github.com/pkg/errors" "github.com/ugorji/go/codec" + chainagnostictypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" htrktypes "github.com/smartcontractkit/chainlink/v2/common/headtracker/types" commontypes "github.com/smartcontractkit/chainlink/v2/common/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types/internal/blocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" @@ -198,6 +201,9 @@ func (h *Head) ChainString() string { // String returns a string representation of this head func (h *Head) String() string { + if h == nil { + return "" + } return fmt.Sprintf("Head{Number: %d, Hash: %s, ParentHash: %s}", h.ToInt(), h.Hash.Hex(), h.ParentHash.Hex()) } @@ -325,6 +331,19 @@ func (h *Head) MarshalJSON() ([]byte, error) { return json.Marshal(jsonHead) } +func (h *Head) ToChainAgnosticHead() *chainagnostictypes.Head { + if h == nil { + return nil + } + + return &chainagnostictypes.Head{ + Height: strconv.FormatInt(h.Number, 10), + Hash: h.Hash.Bytes(), + //nolint:gosec // G115 + Timestamp: uint64(h.Timestamp.Unix()), + } +} + // Block represents an ethereum block // This type is only used for the block history estimator, and can be expensive to unmarshal. Don't add unnecessary fields here. type Block struct { diff --git a/core/scripts/go.mod b/core/scripts/go.mod index a8367d0d4d9..2004dd7620d 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -24,7 +24,7 @@ require ( github.com/prometheus/client_golang v1.20.5 github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chainlink-automation v0.8.1 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371 github.com/smartcontractkit/chainlink/deployment v0.0.0-00010101000000-000000000000 github.com/smartcontractkit/chainlink/v2 v2.14.0-mercury-20240807.0.20241106193309-5560cd76211a github.com/smartcontractkit/libocr v0.0.0-20241007185508-adbe57025f12 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 4919877a650..5dd235b828f 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1094,8 +1094,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b h1:4kmZtaQ4fXwduHnw9xk5VmiIOW4nHg/Mx6iidlZJt5o= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 h1:yJNBWCdNL/X8+wEs3TGTBe9gssMmw5FTFxxrlo+0mVo= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371 h1:vnNqMaAvheZgR8IDMGw0QIV1Qen3XTh7IChwW40SNfU= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f/go.mod h1:wHtwSR3F1CQSJJZDQKuqaqFYnvkT+kMyget7dl8Clvo= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e h1:JiETqdNM0bktAUGMc62COwXIaw3rR3M77Me6bBLG0Fg= diff --git a/core/services/relay/evm/chain_reader.go b/core/services/relay/evm/chain_reader.go index df216a11c2b..4de739a44b4 100644 --- a/core/services/relay/evm/chain_reader.go +++ b/core/services/relay/evm/chain_reader.go @@ -197,7 +197,8 @@ func (cr *chainReader) GetLatestValue(ctx context.Context, readName string, conf ptrToValue, isValue := returnVal.(*values.Value) if !isValue { - return binding.GetLatestValue(ctx, common.HexToAddress(address), confidenceLevel, params, returnVal) + _, err = binding.GetLatestValueWithHeadData(ctx, common.HexToAddress(address), confidenceLevel, params, returnVal) + return err } contractType, err := cr.CreateContractType(readName, false) @@ -219,6 +220,37 @@ func (cr *chainReader) GetLatestValue(ctx context.Context, readName string, conf return nil } +func (cr *chainReader) GetLatestValueWithHeadData(ctx context.Context, readName string, confidenceLevel primitives.ConfidenceLevel, params any, returnVal any) (head *commontypes.Head, err error) { + binding, address, err := cr.bindings.GetReader(readName) + if err != nil { + return nil, err + } + + ptrToValue, isValue := returnVal.(*values.Value) + if !isValue { + return binding.GetLatestValueWithHeadData(ctx, common.HexToAddress(address), confidenceLevel, params, returnVal) + } + + contractType, err := cr.CreateContractType(readName, false) + if err != nil { + return nil, err + } + + head, err = cr.GetLatestValueWithHeadData(ctx, readName, confidenceLevel, params, contractType) + if err != nil { + return nil, err + } + + value, err := values.Wrap(contractType) + if err != nil { + return nil, err + } + + *ptrToValue = value + + return head, nil +} + func (cr *chainReader) BatchGetLatestValues(ctx context.Context, request commontypes.BatchGetLatestValuesRequest) (commontypes.BatchGetLatestValuesResult, error) { return cr.bindings.BatchGetLatestValues(ctx, request) } diff --git a/core/services/relay/evm/read/bindings.go b/core/services/relay/evm/read/bindings.go index bfeb84a3799..cf675ee383e 100644 --- a/core/services/relay/evm/read/bindings.go +++ b/core/services/relay/evm/read/bindings.go @@ -20,7 +20,7 @@ import ( type Reader interface { BatchCall(address common.Address, params, retVal any) (Call, error) - GetLatestValue(ctx context.Context, addr common.Address, confidence primitives.ConfidenceLevel, params, returnVal any) error + GetLatestValueWithHeadData(ctx context.Context, addr common.Address, confidence primitives.ConfidenceLevel, params, returnVal any) (*commontypes.Head, error) QueryKey(context.Context, common.Address, query.KeyFilter, query.LimitAndSort, any) ([]commontypes.Sequence, error) Bind(context.Context, ...common.Address) error diff --git a/core/services/relay/evm/read/bindings_test.go b/core/services/relay/evm/read/bindings_test.go index d9cfa91a987..129d3138141 100644 --- a/core/services/relay/evm/read/bindings_test.go +++ b/core/services/relay/evm/read/bindings_test.go @@ -73,9 +73,9 @@ func TestBindingsRegistry(t *testing.T) { mReg.EXPECT().HasFilter(mock.Anything).Return(false) mReg.EXPECT().RegisterFilter(mock.Anything, mock.Anything).Return(nil) - mRdr0.EXPECT().GetLatestValue(mock.Anything, common.HexToAddress("0x25"), mock.Anything, mock.Anything, mock.Anything).Return(nil) - mRdr0.EXPECT().GetLatestValue(mock.Anything, common.HexToAddress("0x24"), mock.Anything, mock.Anything, mock.Anything).Return(nil) - mRdr1.EXPECT().GetLatestValue(mock.Anything, common.HexToAddress("0x26"), mock.Anything, mock.Anything, mock.Anything).Return(nil) + mRdr0.EXPECT().GetLatestValueWithHeadData(mock.Anything, common.HexToAddress("0x25"), mock.Anything, mock.Anything, mock.Anything).Return(nil, nil) + mRdr0.EXPECT().GetLatestValueWithHeadData(mock.Anything, common.HexToAddress("0x24"), mock.Anything, mock.Anything, mock.Anything).Return(nil, nil) + mRdr1.EXPECT().GetLatestValueWithHeadData(mock.Anything, common.HexToAddress("0x26"), mock.Anything, mock.Anything, mock.Anything).Return(nil, nil) // part of the init phase of chain reader require.NoError(t, named.AddReader(contractName1, methodName1, mRdr0)) @@ -100,9 +100,12 @@ func TestBindingsRegistry(t *testing.T) { rdr2, _, err := named.GetReader(bindings[0].ReadIdentifier(methodName2)) require.NoError(t, err) - require.NoError(t, rdr1.GetLatestValue(context.Background(), common.HexToAddress("0x25"), primitives.Finalized, nil, nil)) - require.NoError(t, rdr1.GetLatestValue(context.Background(), common.HexToAddress("0x24"), primitives.Finalized, nil, nil)) - require.NoError(t, rdr2.GetLatestValue(context.Background(), common.HexToAddress("0x26"), primitives.Finalized, nil, nil)) + _, err = rdr1.GetLatestValueWithHeadData(context.Background(), common.HexToAddress("0x25"), primitives.Finalized, nil, nil) + require.NoError(t, err) + _, err = rdr1.GetLatestValueWithHeadData(context.Background(), common.HexToAddress("0x24"), primitives.Finalized, nil, nil) + require.NoError(t, err) + _, err = rdr2.GetLatestValueWithHeadData(context.Background(), common.HexToAddress("0x26"), primitives.Finalized, nil, nil) + require.NoError(t, err) mBatch.AssertExpectations(t) mRdr0.AssertExpectations(t) diff --git a/core/services/relay/evm/read/event.go b/core/services/relay/evm/read/event.go index a1678fbb4b9..c37b979d7ea 100644 --- a/core/services/relay/evm/read/event.go +++ b/core/services/relay/evm/read/event.go @@ -233,7 +233,7 @@ func (b *EventBinding) BatchCall(_ common.Address, _, _ any) (Call, error) { return Call{}, fmt.Errorf("%w: events are not yet supported in batch get latest values", commontypes.ErrInvalidType) } -func (b *EventBinding) GetLatestValue(ctx context.Context, address common.Address, confidenceLevel primitives.ConfidenceLevel, params, into any) (err error) { +func (b *EventBinding) GetLatestValueWithHeadData(ctx context.Context, address common.Address, confidenceLevel primitives.ConfidenceLevel, params, into any) (head *commontypes.Head, err error) { var ( confs evmtypes.Confirmations result *string @@ -256,24 +256,24 @@ func (b *EventBinding) GetLatestValue(ctx context.Context, address common.Addres }() if err = b.validateBound(address); err != nil { - return err + return nil, err } confs, err = confidenceToConfirmations(b.confirmationsMapping, confidenceLevel) if err != nil { - return err + return nil, err } topicTypeID := codec.WrapItemType(b.contractName, b.eventName, true) onChainTypedVal, err := b.toNativeOnChainType(topicTypeID, params) if err != nil { - return err + return nil, err } filterTopics, err := b.extractFilterTopics(topicTypeID, onChainTypedVal) if err != nil { - return err + return nil, err } var log *logpoller.Log @@ -281,26 +281,30 @@ func (b *EventBinding) GetLatestValue(ctx context.Context, address common.Addres var hashedTopics []common.Hash hashedTopics, err = b.hashTopics(topicTypeID, filterTopics) if err != nil { - return err + return nil, err } if log, err = b.getLatestLog(ctx, address, confs, hashedTopics); err != nil { - return err + return nil, err } } else { if log, err = b.lp.LatestLogByEventSigWithConfs(ctx, b.hash, address, confs); err != nil { - return wrapInternalErr(err) + return nil, wrapInternalErr(err) } } - if err := b.decodeLog(ctx, log, into); err != nil { + if err = b.decodeLog(ctx, log, into); err != nil { encoded := hex.EncodeToString(log.Data) result = &encoded - - return err + return nil, err } - return nil + return &commontypes.Head{ + Height: strconv.FormatInt(log.BlockNumber, 10), + Hash: log.BlockHash.Bytes(), + //nolint:gosec // G115 + Timestamp: uint64(log.BlockTimestamp.Unix()), + }, nil } func (b *EventBinding) QueryKey(ctx context.Context, address common.Address, filter query.KeyFilter, limitAndSort query.LimitAndSort, sequenceDataType any) (sequences []commontypes.Sequence, err error) { diff --git a/core/services/relay/evm/read/method.go b/core/services/relay/evm/read/method.go index fc7886b74b7..393077c6d3f 100644 --- a/core/services/relay/evm/read/method.go +++ b/core/services/relay/evm/read/method.go @@ -121,14 +121,19 @@ func (b *MethodBinding) BatchCall(address common.Address, params, retVal any) (C }, nil } -func (b *MethodBinding) GetLatestValue(ctx context.Context, addr common.Address, confidenceLevel primitives.ConfidenceLevel, params, returnVal any) error { +func (b *MethodBinding) GetLatestValueWithHeadData(ctx context.Context, addr common.Address, confidenceLevel primitives.ConfidenceLevel, params, returnVal any) (*commontypes.Head, error) { if !b.isBound(addr) { - return fmt.Errorf("%w: %w", commontypes.ErrInvalidConfig, newUnboundAddressErr(addr.Hex(), b.contractName, b.method)) + return nil, fmt.Errorf("%w: %w", commontypes.ErrInvalidConfig, newUnboundAddressErr(addr.Hex(), b.contractName, b.method)) } - block, err := b.blockNumberFromConfidence(ctx, confidenceLevel) + block, confirmations, err := b.blockAndConfirmationsFromConfidence(ctx, confidenceLevel) if err != nil { - return err + return nil, err + } + + var blockNum *big.Int + if block != nil && confirmations != evmtypes.Unconfirmed { + blockNum = big.NewInt(block.Number) } data, err := b.codec.Encode(ctx, params, codec.WrapItemType(b.contractName, b.method, true)) @@ -141,9 +146,9 @@ func (b *MethodBinding) GetLatestValue(ctx context.Context, addr common.Address, ReadName: b.method, Params: params, ReturnVal: returnVal, - }, block.String(), false) + }, blockNum.String(), false) - return callErr + return nil, callErr } callMsg := ethereum.CallMsg{ @@ -152,7 +157,7 @@ func (b *MethodBinding) GetLatestValue(ctx context.Context, addr common.Address, Data: data, } - bytes, err := b.client.CallContract(ctx, callMsg, block) + bytes, err := b.client.CallContract(ctx, callMsg, blockNum) if err != nil { callErr := newErrorFromCall( fmt.Errorf("%w: contract call: %s", commontypes.ErrInvalidType, err.Error()), @@ -162,9 +167,9 @@ func (b *MethodBinding) GetLatestValue(ctx context.Context, addr common.Address, ReadName: b.method, Params: params, ReturnVal: returnVal, - }, block.String(), false) + }, blockNum.String(), false) - return callErr + return nil, callErr } if err = b.codec.Decode(ctx, bytes, returnVal, codec.WrapItemType(b.contractName, b.method, false)); err != nil { @@ -176,15 +181,15 @@ func (b *MethodBinding) GetLatestValue(ctx context.Context, addr common.Address, ReadName: b.method, Params: params, ReturnVal: returnVal, - }, block.String(), false) + }, blockNum.String(), false) strResult := hexutil.Encode(bytes) callErr.Result = &strResult - return callErr + return nil, callErr } - return nil + return block.ToChainAgnosticHead(), nil } func (b *MethodBinding) QueryKey( @@ -200,31 +205,31 @@ func (b *MethodBinding) QueryKey( func (b *MethodBinding) Register(_ context.Context) error { return nil } func (b *MethodBinding) Unregister(_ context.Context) error { return nil } -func (b *MethodBinding) blockNumberFromConfidence(ctx context.Context, confidenceLevel primitives.ConfidenceLevel) (*big.Int, error) { +func (b *MethodBinding) blockAndConfirmationsFromConfidence(ctx context.Context, confidenceLevel primitives.ConfidenceLevel) (*evmtypes.Head, evmtypes.Confirmations, error) { confirmations, err := confidenceToConfirmations(b.confirmationsMapping, confidenceLevel) if err != nil { - err = fmt.Errorf("%w: contract: %s; method: %s;", err, b.contractName, b.method) + err = fmt.Errorf("%w: contract: %s; method: %s", err, b.contractName, b.method) if confidenceLevel == primitives.Unconfirmed { b.lggr.Debugw("Falling back to default contract call behaviour that calls latest state", "contract", b.contractName, "method", b.method, "err", err) - return nil, nil + return nil, 0, err } - return nil, err + return nil, 0, err } - _, finalized, err := b.ht.LatestAndFinalizedBlock(ctx) + latest, finalized, err := b.ht.LatestAndFinalizedBlock(ctx) if err != nil { - return nil, fmt.Errorf("%w: head tracker: %w", commontypes.ErrInternal, err) + return nil, 0, fmt.Errorf("%w: head tracker: %w", commontypes.ErrInternal, err) } if confirmations == evmtypes.Finalized { - return big.NewInt(finalized.Number), nil + return finalized, confirmations, nil } else if confirmations == evmtypes.Unconfirmed { - return nil, nil + return latest, confirmations, nil } - return nil, fmt.Errorf("%w: [unknown evm confirmations]: %v; contract: %s; method: %s;", commontypes.ErrInvalidConfig, confirmations, b.contractName, b.method) + return nil, 0, fmt.Errorf("%w: [unknown evm confirmations]: %v; contract: %s; method: %s", commontypes.ErrInvalidConfig, confirmations, b.contractName, b.method) } func (b *MethodBinding) isBound(binding common.Address) bool { diff --git a/core/services/relay/evm/read/mocks/reader.go b/core/services/relay/evm/read/mocks/reader.go index b259b3cdcb1..79df3cf4025 100644 --- a/core/services/relay/evm/read/mocks/reader.go +++ b/core/services/relay/evm/read/mocks/reader.go @@ -150,52 +150,64 @@ func (_c *Reader_Bind_Call) RunAndReturn(run func(context.Context, ...common.Add return _c } -// GetLatestValue provides a mock function with given fields: ctx, addr, confidence, params, returnVal -func (_m *Reader) GetLatestValue(ctx context.Context, addr common.Address, confidence primitives.ConfidenceLevel, params any, returnVal any) error { +// GetLatestValueWithHeadData provides a mock function with given fields: ctx, addr, confidence, params, returnVal +func (_m *Reader) GetLatestValueWithHeadData(ctx context.Context, addr common.Address, confidence primitives.ConfidenceLevel, params any, returnVal any) (*types.Head, error) { ret := _m.Called(ctx, addr, confidence, params, returnVal) if len(ret) == 0 { - panic("no return value specified for GetLatestValue") + panic("no return value specified for GetLatestValueWithHeadData") } - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, common.Address, primitives.ConfidenceLevel, any, any) error); ok { + var r0 *types.Head + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, common.Address, primitives.ConfidenceLevel, any, any) (*types.Head, error)); ok { + return rf(ctx, addr, confidence, params, returnVal) + } + if rf, ok := ret.Get(0).(func(context.Context, common.Address, primitives.ConfidenceLevel, any, any) *types.Head); ok { r0 = rf(ctx, addr, confidence, params, returnVal) } else { - r0 = ret.Error(0) + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Head) + } } - return r0 + if rf, ok := ret.Get(1).(func(context.Context, common.Address, primitives.ConfidenceLevel, any, any) error); ok { + r1 = rf(ctx, addr, confidence, params, returnVal) + } else { + r1 = ret.Error(1) + } + + return r0, r1 } -// Reader_GetLatestValue_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLatestValue' -type Reader_GetLatestValue_Call struct { +// Reader_GetLatestValueWithHeadData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetLatestValueWithHeadData' +type Reader_GetLatestValueWithHeadData_Call struct { *mock.Call } -// GetLatestValue is a helper method to define mock.On call +// GetLatestValueWithHeadData is a helper method to define mock.On call // - ctx context.Context // - addr common.Address // - confidence primitives.ConfidenceLevel // - params any // - returnVal any -func (_e *Reader_Expecter) GetLatestValue(ctx interface{}, addr interface{}, confidence interface{}, params interface{}, returnVal interface{}) *Reader_GetLatestValue_Call { - return &Reader_GetLatestValue_Call{Call: _e.mock.On("GetLatestValue", ctx, addr, confidence, params, returnVal)} +func (_e *Reader_Expecter) GetLatestValueWithHeadData(ctx interface{}, addr interface{}, confidence interface{}, params interface{}, returnVal interface{}) *Reader_GetLatestValueWithHeadData_Call { + return &Reader_GetLatestValueWithHeadData_Call{Call: _e.mock.On("GetLatestValueWithHeadData", ctx, addr, confidence, params, returnVal)} } -func (_c *Reader_GetLatestValue_Call) Run(run func(ctx context.Context, addr common.Address, confidence primitives.ConfidenceLevel, params any, returnVal any)) *Reader_GetLatestValue_Call { +func (_c *Reader_GetLatestValueWithHeadData_Call) Run(run func(ctx context.Context, addr common.Address, confidence primitives.ConfidenceLevel, params any, returnVal any)) *Reader_GetLatestValueWithHeadData_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].(common.Address), args[2].(primitives.ConfidenceLevel), args[3].(any), args[4].(any)) }) return _c } -func (_c *Reader_GetLatestValue_Call) Return(_a0 error) *Reader_GetLatestValue_Call { - _c.Call.Return(_a0) +func (_c *Reader_GetLatestValueWithHeadData_Call) Return(_a0 *types.Head, _a1 error) *Reader_GetLatestValueWithHeadData_Call { + _c.Call.Return(_a0, _a1) return _c } -func (_c *Reader_GetLatestValue_Call) RunAndReturn(run func(context.Context, common.Address, primitives.ConfidenceLevel, any, any) error) *Reader_GetLatestValue_Call { +func (_c *Reader_GetLatestValueWithHeadData_Call) RunAndReturn(run func(context.Context, common.Address, primitives.ConfidenceLevel, any, any) (*types.Head, error)) *Reader_GetLatestValueWithHeadData_Call { _c.Call.Return(run) return _c } diff --git a/deployment/go.mod b/deployment/go.mod index 3ca839c88a0..dbfb7e8472f 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -24,7 +24,7 @@ require ( github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240926212305-a6deabdfce86 github.com/smartcontractkit/chain-selectors v1.0.27 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371 github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 diff --git a/deployment/go.sum b/deployment/go.sum index 6cf64ab085a..20fcdbd861a 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1384,8 +1384,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b h1:4kmZtaQ4fXwduHnw9xk5VmiIOW4nHg/Mx6iidlZJt5o= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 h1:yJNBWCdNL/X8+wEs3TGTBe9gssMmw5FTFxxrlo+0mVo= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371 h1:vnNqMaAvheZgR8IDMGw0QIV1Qen3XTh7IChwW40SNfU= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f/go.mod h1:wHtwSR3F1CQSJJZDQKuqaqFYnvkT+kMyget7dl8Clvo= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e h1:JiETqdNM0bktAUGMc62COwXIaw3rR3M77Me6bBLG0Fg= diff --git a/go.mod b/go.mod index e2713001ca0..74e16a69202 100644 --- a/go.mod +++ b/go.mod @@ -77,7 +77,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.27 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371 github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e github.com/smartcontractkit/chainlink-feeds v0.1.1 diff --git a/go.sum b/go.sum index 1b03627496b..ddf3d1a8c39 100644 --- a/go.sum +++ b/go.sum @@ -1078,8 +1078,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b h1:4kmZtaQ4fXwduHnw9xk5VmiIOW4nHg/Mx6iidlZJt5o= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 h1:yJNBWCdNL/X8+wEs3TGTBe9gssMmw5FTFxxrlo+0mVo= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371 h1:vnNqMaAvheZgR8IDMGw0QIV1Qen3XTh7IChwW40SNfU= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f/go.mod h1:wHtwSR3F1CQSJJZDQKuqaqFYnvkT+kMyget7dl8Clvo= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e h1:JiETqdNM0bktAUGMc62COwXIaw3rR3M77Me6bBLG0Fg= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 32a7e666109..875ea7dcfe3 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -37,7 +37,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.27 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371 github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.2 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 31c4e6c41a6..9db5e175661 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1405,8 +1405,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b h1:4kmZtaQ4fXwduHnw9xk5VmiIOW4nHg/Mx6iidlZJt5o= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 h1:yJNBWCdNL/X8+wEs3TGTBe9gssMmw5FTFxxrlo+0mVo= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371 h1:vnNqMaAvheZgR8IDMGw0QIV1Qen3XTh7IChwW40SNfU= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f/go.mod h1:wHtwSR3F1CQSJJZDQKuqaqFYnvkT+kMyget7dl8Clvo= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e h1:JiETqdNM0bktAUGMc62COwXIaw3rR3M77Me6bBLG0Fg= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 870615462a4..54fed1df1b2 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -17,7 +17,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.33.0 github.com/slack-go/slack v0.15.0 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 + github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.5 github.com/smartcontractkit/chainlink-testing-framework/wasp v1.50.2 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 57d80e527cc..b287474056e 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1394,8 +1394,8 @@ github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgB github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b h1:4kmZtaQ4fXwduHnw9xk5VmiIOW4nHg/Mx6iidlZJt5o= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6 h1:yJNBWCdNL/X8+wEs3TGTBe9gssMmw5FTFxxrlo+0mVo= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241112140826-0e2daed34ef6/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371 h1:vnNqMaAvheZgR8IDMGw0QIV1Qen3XTh7IChwW40SNfU= +github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f/go.mod h1:wHtwSR3F1CQSJJZDQKuqaqFYnvkT+kMyget7dl8Clvo= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e h1:JiETqdNM0bktAUGMc62COwXIaw3rR3M77Me6bBLG0Fg= From 24c3f90cd015775a8099bd2967992dd26f1e5e38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Hrastnik?= Date: Thu, 14 Nov 2024 04:11:24 +0900 Subject: [PATCH 13/14] deployments: keystone: Leverage job-distributor (#15179) * deployment: Support other chain types in CreateCCIPOCRSupportedChains * nix: Upgrade to postgres 15 * keystone: Migrate from CLO to JD * CLO compat * Allow setting labels on nodes * Rename function * Tag nodes with p2p_id for easy lookup * Lookup nodes according to p2p_id * Implement label & id filtering in the memory job client * Update the CLO job client as well * go mod tidy * Fix DeployCLO * Fix CLO job client test * add TODOs * fix up tests again * Fix compilation, remove nodeIdToNop indirection * fix TestDeployCLO * add clo utils to bridge tooling gap * add utils to remap clo node id to peer id * fix p2p filter in clo jd impl; fix mis-matched id vs p2p usage * Add credential support to jd client * go mod tidy * rm pointer lib --------- Co-authored-by: krehermann <16602512+krehermann@users.noreply.github.com> --- deployment/ccip/test_helpers.go | 4 +- deployment/environment/clo/env.go | 137 ----- .../environment/clo/offchain_client_impl.go | 98 +++- .../clo/offchain_client_impl_test.go | 191 +++++-- deployment/environment/clo/utils.go | 69 +++ deployment/environment/clo/utils_test.go | 168 ++++++ deployment/environment/devenv/don.go | 84 ++- deployment/environment/devenv/don_test.go | 19 + deployment/environment/devenv/jd.go | 32 +- deployment/environment/memory/chain.go | 2 +- deployment/environment/memory/environment.go | 27 +- deployment/environment/memory/job_client.go | 167 +++++- deployment/environment/memory/node.go | 85 ++- deployment/environment/memory/node_test.go | 2 +- deployment/environment/memory/sim.go | 34 +- .../environment/web/sdk/client/client.go | 30 +- .../web/sdk/internal/generated/generated.go | 91 +++ .../web/sdk/internal/genqlient.graphql | 16 +- deployment/go.mod | 3 +- deployment/keystone/changeset/deploy_ocr3.go | 6 +- .../keystone/changeset/internal/test/utils.go | 2 +- .../changeset/internal/update_don_test.go | 116 ++-- .../changeset/internal/update_nodes_test.go | 2 +- deployment/keystone/changeset/types.go | 17 +- .../changeset/update_node_capabilities.go | 4 +- deployment/keystone/deploy.go | 164 +++++- deployment/keystone/deploy_test.go | 271 ++++++++- deployment/keystone/types.go | 184 +++--- deployment/keystone/types_test.go | 540 +++++++++--------- shell.nix | 2 +- 30 files changed, 1769 insertions(+), 798 deletions(-) delete mode 100644 deployment/environment/clo/env.go create mode 100644 deployment/environment/clo/utils_test.go create mode 100644 deployment/environment/devenv/don_test.go diff --git a/deployment/ccip/test_helpers.go b/deployment/ccip/test_helpers.go index cfa637ee9b0..f12a475bc2f 100644 --- a/deployment/ccip/test_helpers.go +++ b/deployment/ccip/test_helpers.go @@ -170,14 +170,14 @@ func NewMemoryEnvironment(t *testing.T, lggr logger.Logger, numChains int, numNo require.GreaterOrEqual(t, numChains, 2, "numChains must be at least 2 for home and feed chains") require.GreaterOrEqual(t, numNodes, 4, "numNodes must be at least 4") ctx := testcontext.Get(t) - chains, evmChains := memory.NewMemoryChains(t, numChains) + chains := memory.NewMemoryChains(t, numChains) homeChainSel, feedSel := allocateCCIPChainSelectors(chains) replayBlocks, err := LatestBlocksByChain(ctx, chains) require.NoError(t, err) ab := deployment.NewMemoryAddressBook() crConfig := DeployTestContracts(t, lggr, ab, homeChainSel, feedSel, chains) - nodes := memory.NewNodes(t, zapcore.InfoLevel, evmChains, numNodes, 1, crConfig) + nodes := memory.NewNodes(t, zapcore.InfoLevel, chains, numNodes, 1, crConfig) for _, node := range nodes { require.NoError(t, node.App.Start(ctx)) t.Cleanup(func() { diff --git a/deployment/environment/clo/env.go b/deployment/environment/clo/env.go deleted file mode 100644 index d1683ad4e1e..00000000000 --- a/deployment/environment/clo/env.go +++ /dev/null @@ -1,137 +0,0 @@ -package clo - -import ( - "strconv" - "testing" - - "github.com/test-go/testify/require" - - "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink/deployment" - "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" - "github.com/smartcontractkit/chainlink/deployment/environment/memory" -) - -type DonEnvConfig struct { - DonName string - Chains map[uint64]deployment.Chain - Logger logger.Logger - Nops []*models.NodeOperator -} - -func NewDonEnv(t *testing.T, cfg DonEnvConfig) *deployment.Environment { - // no bootstraps in the don as far as capabilities registry is concerned - for _, nop := range cfg.Nops { - for _, node := range nop.Nodes { - for _, chain := range node.ChainConfigs { - if chain.Ocr2Config.IsBootstrap { - t.Fatalf("Don nodes should not be bootstraps nop %s node %s chain %s", nop.ID, node.ID, chain.Network.ChainID) - } - } - } - } - out := deployment.NewEnvironment( - cfg.DonName, - cfg.Logger, - deployment.NewMemoryAddressBook(), - cfg.Chains, - make([]string, 0), - NewJobClient(cfg.Logger, cfg.Nops), - ) - // assume that all the nodes in the provided input nops are part of the don - for _, nop := range cfg.Nops { - for _, node := range nop.Nodes { - out.NodeIDs = append(out.NodeIDs, node.ID) - } - } - - return out -} - -func NewDonEnvWithMemoryChains(t *testing.T, cfg DonEnvConfig, ignore func(*models.NodeChainConfig) bool) *deployment.Environment { - e := NewDonEnv(t, cfg) - // overwrite the chains with memory chains - chains := make(map[uint64]struct{}) - for _, nop := range cfg.Nops { - for _, node := range nop.Nodes { - for _, chain := range node.ChainConfigs { - if ignore(chain) { - continue - } - id, err := strconv.ParseUint(chain.Network.ChainID, 10, 64) - require.NoError(t, err, "failed to parse chain id to uint64") - chains[id] = struct{}{} - } - } - } - var cs []uint64 - for c := range chains { - cs = append(cs, c) - } - memoryChains := memory.NewMemoryChainsWithChainIDs(t, cs) - e.Chains = memoryChains - return e -} - -// MultiDonEnvironment is a single logical deployment environment (like dev, testnet, prod,...). -// It represents the idea that different nodesets host different capabilities. -// Each element in the DonEnv is a logical set of nodes that host the same capabilities. -// This model allows us to reuse the existing Environment abstraction while supporting multiple nodesets at -// expense of slightly abusing the original abstraction. Specifically, the abuse is that -// each Environment in the DonToEnv map is a subset of the target deployment environment. -// One element cannot represent dev and other testnet for example. -type MultiDonEnvironment struct { - donToEnv map[string]*deployment.Environment - Logger logger.Logger - // hacky but temporary to transition to Environment abstraction. set by New - Chains map[uint64]deployment.Chain -} - -func (mde MultiDonEnvironment) Flatten(name string) *deployment.Environment { - // TODO: KS-460 integrate with the clo offchain client impl - // may need to extend the Environment abstraction use maps rather than slices for Nodes - // somehow we need to capture the fact that each nodes belong to nodesets which have different capabilities - // purposely nil to catch misuse until we do that work - return deployment.NewEnvironment( - name, - mde.Logger, - deployment.NewMemoryAddressBook(), - mde.Chains, - nil, - nil, - ) -} - -func newMultiDonEnvironment(logger logger.Logger, donToEnv map[string]*deployment.Environment) *MultiDonEnvironment { - chains := make(map[uint64]deployment.Chain) - for _, env := range donToEnv { - for sel, chain := range env.Chains { - if _, exists := chains[sel]; !exists { - chains[sel] = chain - } - } - } - return &MultiDonEnvironment{ - donToEnv: donToEnv, - Logger: logger, - Chains: chains, - } -} - -func NewTestEnv(t *testing.T, lggr logger.Logger, dons map[string]*deployment.Environment) *MultiDonEnvironment { - for _, don := range dons { - //don := don - seen := make(map[uint64]deployment.Chain) - // ensure that generated chains are the same for all environments. this ensures that he in memory representation - // points to a common object for all dons given the same selector. - for sel, chain := range don.Chains { - c, exists := seen[sel] - if exists { - don.Chains[sel] = c - } else { - seen[sel] = chain - } - } - } - return newMultiDonEnvironment(lggr, dons) -} diff --git a/deployment/environment/clo/offchain_client_impl.go b/deployment/environment/clo/offchain_client_impl.go index e670663b925..16c50126398 100644 --- a/deployment/environment/clo/offchain_client_impl.go +++ b/deployment/environment/clo/offchain_client_impl.go @@ -2,6 +2,9 @@ package clo import ( "context" + "fmt" + "slices" + "strings" "go.uber.org/zap" "google.golang.org/grpc" @@ -10,6 +13,7 @@ import ( csav1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/csa" jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" nodev1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node" + "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/shared/ptypes" "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" ) @@ -60,39 +64,68 @@ func (j JobClient) GetNode(ctx context.Context, in *nodev1.GetNodeRequest, opts } func (j JobClient) ListNodes(ctx context.Context, in *nodev1.ListNodesRequest, opts ...grpc.CallOption) (*nodev1.ListNodesResponse, error) { - //TODO CCIP-3108 - var fiterIds map[string]struct{} - include := func(id string) bool { - if in.Filter == nil || len(in.Filter.Ids) == 0 { + include := func(node *nodev1.Node) bool { + if in.Filter == nil { return true } - // lazy init - if len(fiterIds) == 0 { - for _, id := range in.Filter.Ids { - fiterIds[id] = struct{}{} + if len(in.Filter.Ids) > 0 { + idx := slices.IndexFunc(in.Filter.Ids, func(id string) bool { + return node.Id == id + }) + if idx < 0 { + return false } } - _, ok := fiterIds[id] - return ok + for _, selector := range in.Filter.Selectors { + idx := slices.IndexFunc(node.Labels, func(label *ptypes.Label) bool { + return label.Key == selector.Key + }) + if idx < 0 { + return false + } + label := node.Labels[idx] + + switch selector.Op { + case ptypes.SelectorOp_IN: + values := strings.Split(*selector.Value, ",") + found := slices.Contains(values, *label.Value) + if !found { + return false + } + default: + panic("unimplemented selector") + } + } + return true } var nodes []*nodev1.Node for _, nop := range j.NodeOperators { for _, n := range nop.Nodes { - if include(n.ID) { - nodes = append(nodes, &nodev1.Node{ - Id: n.ID, - Name: n.Name, - PublicKey: *n.PublicKey, // is this the correct val? - IsEnabled: n.Enabled, - IsConnected: n.Connected, - }) + p2pId, err := NodeP2PId(n) + if err != nil { + return nil, fmt.Errorf("failed to get p2p id for node %s: %w", n.ID, err) + } + node := &nodev1.Node{ + Id: n.ID, + Name: n.Name, + PublicKey: *n.PublicKey, + IsEnabled: n.Enabled, + IsConnected: n.Connected, + Labels: []*ptypes.Label{ + { + Key: "p2p_id", + Value: &p2pId, // here n.ID is also peer ID + }, + }, + } + if include(node) { + nodes = append(nodes, node) } } } return &nodev1.ListNodesResponse{ Nodes: nodes, }, nil - } func (j JobClient) ListNodeChainConfigs(ctx context.Context, in *nodev1.ListNodeChainConfigsRequest, opts ...grpc.CallOption) (*nodev1.ListNodeChainConfigsResponse, error) { @@ -160,13 +193,18 @@ type GetNodeOperatorsResponse struct { NodeOperators []*models.NodeOperator `json:"nodeOperators"` } -func NewJobClient(lggr logger.Logger, nops []*models.NodeOperator) *JobClient { +type JobClientConfig struct { + Nops []*models.NodeOperator +} + +func NewJobClient(lggr logger.Logger, cfg JobClientConfig) *JobClient { + c := &JobClient{ - NodeOperators: nops, + NodeOperators: cfg.Nops, nodesByID: make(map[string]*models.Node), lggr: lggr, } - for _, nop := range nops { + for _, nop := range c.NodeOperators { for _, n := range nop.Nodes { node := n c.nodesByID[n.ID] = node // maybe should use the public key instead? @@ -184,10 +222,24 @@ func cloNodeToChainConfigs(n *models.Node) []*nodev1.ChainConfig { } func cloChainCfgToJDChainCfg(ccfg *models.NodeChainConfig) *nodev1.ChainConfig { + var ctype nodev1.ChainType + switch ccfg.Network.ChainType { + case models.ChainTypeEvm: + ctype = nodev1.ChainType_CHAIN_TYPE_EVM + case models.ChainTypeSolana: + ctype = nodev1.ChainType_CHAIN_TYPE_SOLANA + case models.ChainTypeStarknet: + ctype = nodev1.ChainType_CHAIN_TYPE_STARKNET + case models.ChainTypeAptos: + ctype = nodev1.ChainType_CHAIN_TYPE_APTOS + default: + panic(fmt.Sprintf("Unsupported chain family %v", ccfg.Network.ChainType)) + } + return &nodev1.ChainConfig{ Chain: &nodev1.Chain{ Id: ccfg.Network.ChainID, - Type: nodev1.ChainType_CHAIN_TYPE_EVM, // TODO: write conversion func from clo to jd tyes + Type: ctype, }, AccountAddress: ccfg.AccountAddress, AdminAddress: ccfg.AdminAddress, diff --git a/deployment/environment/clo/offchain_client_impl_test.go b/deployment/environment/clo/offchain_client_impl_test.go index 3c9277d9fb0..f2d6fcf6f41 100644 --- a/deployment/environment/clo/offchain_client_impl_test.go +++ b/deployment/environment/clo/offchain_client_impl_test.go @@ -10,11 +10,19 @@ import ( "google.golang.org/grpc" nodev1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node" + "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/shared/ptypes" "github.com/smartcontractkit/chainlink/deployment/environment/clo" "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" "github.com/smartcontractkit/chainlink/v2/core/logger" ) +var ( + p2pid_1 = "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE7807807807" + p2pid_2 = "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE6868686868" + p2pid_3 = "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE9999999999" + p2pid_4 = "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE1000000000" +) + var testNops = ` [ { @@ -26,6 +34,20 @@ var testNops = ` "name": "Chainlink Sepolia Prod Keystone One 9", "publicKey": "412dc6fe48ea4e34baaa77da2e3b032d39b938597b6f3d61fe7ed183a827a431", "connected": true, + "chainConfigs": [ + { + "network": { + "id": "140", + "chainID": "421614", + "chainType": "EVM" + }, + "ocr2Config": { + "p2pKeyBundle": { + "peerID": "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE7807807807" + } + } + } + ], "supportedProducts": [ "WORKFLOW", "OCR3_CAPABILITY" @@ -34,51 +56,93 @@ var testNops = ` ], "createdAt": "2024-08-14T19:00:07.113658Z" }, - { - "id": "68", - "name": "Chainlink Keystone Node Operator 8", - "nodes": [ - { - "id": "781", - "name": "Chainlink Sepolia Prod Keystone One 8", - "publicKey": "1141dd1e46797ced9b0fbad49115f18507f6f6e6e3cc86e7e5ba169e58645adc", - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ] - } - ], - "createdAt": "2024-08-14T20:26:37.622463Z" - }, - { - "id": "999", - "name": "Chainlink Keystone Node Operator 100", - "nodes": [ - { - "id": "999", - "name": "Chainlink Sepolia Prod Keystone One 999", - "publicKey": "9991dd1e46797ced9b0fbad49115f18507f6f6e6e3cc86e7e5ba169e58999999", - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ] - }, - { - "id": "1000", - "name": "Chainlink Sepolia Prod Keystone One 1000", - "publicKey": "1000101e46797ced9b0fbad49115f18507f6f6e6e3cc86e7e5ba169e58641000", - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ] - } - ], - "createdAt": "2024-08-14T20:26:37.622463Z" - } -] + { + "id": "68", + "name": "Chainlink Keystone Node Operator 8", + "nodes": [ + { + "id": "781", + "name": "Chainlink Sepolia Prod Keystone One 8", + "publicKey": "1141dd1e46797ced9b0fbad49115f18507f6f6e6e3cc86e7e5ba169e58645adc", + "connected": true, + "chainConfigs": [ + { + "network": { + "id": "140", + "chainID": "421614", + "chainType": "EVM" + }, + "ocr2Config": { + "p2pKeyBundle": { + "peerID": "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE6868686868" + } + } + } + ], + "supportedProducts": [ + "WORKFLOW", + "OCR3_CAPABILITY" + ] + } + ], + "createdAt": "2024-08-14T20:26:37.622463Z" + }, + { + "id": "999", + "name": "Chainlink Keystone Node Operator 100", + "nodes": [ + { + "id": "999", + "name": "Chainlink Sepolia Prod Keystone One 999", + "publicKey": "9991dd1e46797ced9b0fbad49115f18507f6f6e6e3cc86e7e5ba169e58999999", + "connected": true, + "chainConfigs": [ + { + "network": { + "id": "140", + "chainID": "421614", + "chainType": "EVM" + }, + "ocr2Config": { + "p2pKeyBundle": { + "peerID": "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE9999999999" + } + } + } + ], + "supportedProducts": [ + "WORKFLOW", + "OCR3_CAPABILITY" + ] + }, + { + "id": "1000", + "name": "Chainlink Sepolia Prod Keystone One 1000", + "publicKey": "1000101e46797ced9b0fbad49115f18507f6f6e6e3cc86e7e5ba169e58641000", + "connected": true, + "chainConfigs": [ + { + "network": { + "id": "140", + "chainID": "421614", + "chainType": "EVM" + }, + "ocr2Config": { + "p2pKeyBundle": { + "peerID": "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE1000000000" + } + } + } + ], + "supportedProducts": [ + "WORKFLOW", + "OCR3_CAPABILITY" + ] + } + ], + "createdAt": "2024-08-14T20:26:37.622463Z" + } +] ` func parseTestNops(t *testing.T) []*models.NodeOperator { @@ -94,7 +158,8 @@ func TestJobClient_ListNodes(t *testing.T) { nops := parseTestNops(t) type fields struct { - NodeOperators []*models.NodeOperator + NodeOperators []*models.NodeOperator + RemapNodeIDsToPeerIDs bool } type args struct { ctx context.Context @@ -135,6 +200,12 @@ func TestJobClient_ListNodes(t *testing.T) { Name: "Chainlink Sepolia Prod Keystone One 9", PublicKey: "412dc6fe48ea4e34baaa77da2e3b032d39b938597b6f3d61fe7ed183a827a431", IsConnected: true, + Labels: []*ptypes.Label{ + { + Key: "p2p_id", + Value: &p2pid_1, + }, + }, }, }, }, @@ -155,12 +226,24 @@ func TestJobClient_ListNodes(t *testing.T) { Name: "Chainlink Sepolia Prod Keystone One 9", PublicKey: "412dc6fe48ea4e34baaa77da2e3b032d39b938597b6f3d61fe7ed183a827a431", IsConnected: true, + Labels: []*ptypes.Label{ + { + Key: "p2p_id", + Value: &p2pid_1, + }, + }, }, { Id: "781", Name: "Chainlink Sepolia Prod Keystone One 8", PublicKey: "1141dd1e46797ced9b0fbad49115f18507f6f6e6e3cc86e7e5ba169e58645adc", IsConnected: true, + Labels: []*ptypes.Label{ + { + Key: "p2p_id", + Value: &p2pid_2, + }, + }, }, }, }, @@ -181,12 +264,24 @@ func TestJobClient_ListNodes(t *testing.T) { Name: "Chainlink Sepolia Prod Keystone One 999", PublicKey: "9991dd1e46797ced9b0fbad49115f18507f6f6e6e3cc86e7e5ba169e58999999", IsConnected: true, + Labels: []*ptypes.Label{ + { + Key: "p2p_id", + Value: &p2pid_3, + }, + }, }, { Id: "1000", Name: "Chainlink Sepolia Prod Keystone One 1000", PublicKey: "1000101e46797ced9b0fbad49115f18507f6f6e6e3cc86e7e5ba169e58641000", IsConnected: true, + Labels: []*ptypes.Label{ + { + Key: "p2p_id", + Value: &p2pid_4, + }, + }, }, }, }, @@ -194,7 +289,7 @@ func TestJobClient_ListNodes(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - j := clo.NewJobClient(lggr, tt.fields.NodeOperators) + j := clo.NewJobClient(lggr, clo.JobClientConfig{Nops: tt.fields.NodeOperators}) got, err := j.ListNodes(tt.args.ctx, tt.args.in, tt.args.opts...) if (err != nil) != tt.wantErr { @@ -558,7 +653,7 @@ func TestJobClient_ListNodeChainConfigs(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - j := clo.NewJobClient(lggr, tt.fields.NodeOperators) + j := clo.NewJobClient(lggr, clo.JobClientConfig{Nops: tt.fields.NodeOperators}) got, err := j.ListNodeChainConfigs(tt.args.ctx, tt.args.in, tt.args.opts...) if (err != nil) != tt.wantErr { diff --git a/deployment/environment/clo/utils.go b/deployment/environment/clo/utils.go index 79502ef6706..67be141a6db 100644 --- a/deployment/environment/clo/utils.go +++ b/deployment/environment/clo/utils.go @@ -1,6 +1,8 @@ package clo import ( + "fmt" + jd "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node" "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" ) @@ -30,3 +32,70 @@ func NewChainConfig(chain *models.NodeChainConfig) *jd.ChainConfig { }, } } + +func NodeP2PId(n *models.Node) (string, error) { + p2pIds := make(map[string]struct{}) + for _, cc := range n.ChainConfigs { + if cc.Ocr2Config != nil && cc.Ocr2Config.P2pKeyBundle != nil { + p2pIds[cc.Ocr2Config.P2pKeyBundle.PeerID] = struct{}{} + } + } + if len(p2pIds) == 0 { + return "", fmt.Errorf("no p2p id found for node %s", n.ID) + } + if len(p2pIds) > 1 { + return "", fmt.Errorf("multiple p2p ids found for node %s", n.ID) + } + var p2pId string + for k := range p2pIds { + p2pId = k + break + } + return p2pId, nil +} + +func NodesToPeerIDs(nodes []*models.Node) ([]string, error) { + var p2pIds []string + for _, node := range nodes { + p2pId, err := NodeP2PId(node) + if err != nil { + return nil, err + } + p2pIds = append(p2pIds, p2pId) + } + return p2pIds, nil +} + +func NopsToNodes(nops []*models.NodeOperator) []*models.Node { + var nodes []*models.Node + for _, nop := range nops { + nodes = append(nodes, nop.Nodes...) + } + return nodes +} + +func NopsToPeerIds(nops []*models.NodeOperator) ([]string, error) { + return NodesToPeerIDs(NopsToNodes(nops)) +} + +func SetIdToPeerId(n *models.Node) error { + p2pId, err := NodeP2PId(n) + if err != nil { + return err + } + n.ID = p2pId + return nil +} + +// SetNodeIdsToPeerIds sets the ID of each node in the NOPs to the P2P ID of the node +// It mutates the input NOPs +func SetNodeIdsToPeerIds(nops []*models.NodeOperator) error { + for _, nop := range nops { + for _, n := range nop.Nodes { + if err := SetIdToPeerId(n); err != nil { + return err + } + } + } + return nil +} diff --git a/deployment/environment/clo/utils_test.go b/deployment/environment/clo/utils_test.go new file mode 100644 index 00000000000..e2202d4e14f --- /dev/null +++ b/deployment/environment/clo/utils_test.go @@ -0,0 +1,168 @@ +package clo + +import ( + "testing" + + "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" + "github.com/stretchr/testify/assert" +) + +func TestSetNodeIdsToPeerIds(t *testing.T) { + type args struct { + nops []*models.NodeOperator + } + tests := []struct { + name string + args args + want []*models.NodeOperator + wantErr bool + }{ + { + name: "no nodes", + args: args{ + nops: []*models.NodeOperator{ + { + ID: "nop1", + }, + }, + }, + want: []*models.NodeOperator{ + { + ID: "nop1", + }, + }, + }, + { + name: "error no p2p key bundle", + args: args{ + nops: []*models.NodeOperator{ + { + ID: "nop1", + Nodes: []*models.Node{ + { + ID: "node1", + ChainConfigs: []*models.NodeChainConfig{ + { + Ocr2Config: &models.NodeOCR2Config{}, + }, + }, + }, + }, + }, + }, + }, + wantErr: true, + }, + { + name: "error multiple p2p key bundle", + args: args{ + nops: []*models.NodeOperator{ + { + ID: "nop1", + Nodes: []*models.Node{ + { + ID: "node1", + ChainConfigs: []*models.NodeChainConfig{ + { + Ocr2Config: &models.NodeOCR2Config{ + P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ + PeerID: "peer1", + }, + }, + }, + { + Ocr2Config: &models.NodeOCR2Config{ + P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ + PeerID: "peer2", + }, + }, + }, + }, + }, + }, + }, + }, + }, + wantErr: true, + }, + { + name: "multiple nodes", + args: args{ + nops: []*models.NodeOperator{ + { + ID: "nop1", + Nodes: []*models.Node{ + { + ID: "node1", + ChainConfigs: []*models.NodeChainConfig{ + { + Ocr2Config: &models.NodeOCR2Config{ + P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ + PeerID: "peer1", + }, + }, + }, + }, + }, + { + ID: "node2", + ChainConfigs: []*models.NodeChainConfig{ + { + Ocr2Config: &models.NodeOCR2Config{ + P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ + PeerID: "another peer id", + }, + }, + }, + }, + }, + }, + }, + }, + }, + want: []*models.NodeOperator{ + { + ID: "nop1", + Nodes: []*models.Node{ + { + ID: "peer1", + ChainConfigs: []*models.NodeChainConfig{ + { + Ocr2Config: &models.NodeOCR2Config{ + P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ + PeerID: "peer1", + }, + }, + }, + }, + }, + { + ID: "another peer id", + ChainConfigs: []*models.NodeChainConfig{ + { + Ocr2Config: &models.NodeOCR2Config{ + P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ + PeerID: "another peer id", + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := SetNodeIdsToPeerIds(tt.args.nops) + if (err != nil) != tt.wantErr { + t.Errorf("SetNodeIdsToPeerIds() error = %v, wantErr %v", err, tt.wantErr) + } + if err != nil { + return + } + assert.EqualValues(t, tt.args.nops, tt.want) + }) + } +} diff --git a/deployment/environment/devenv/don.go b/deployment/environment/devenv/don.go index c14216f3894..830f5b921bc 100644 --- a/deployment/environment/devenv/don.go +++ b/deployment/environment/devenv/don.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "github.com/AlekSi/pointer" "github.com/hashicorp/go-multierror" "github.com/rs/zerolog" "github.com/sethvargo/go-retry" @@ -34,6 +33,7 @@ type NodeInfo struct { Name string // name of the node, used to identify the node, helpful in logs AdminAddr string // admin address to send payments to, applicable only for non-bootstrap nodes MultiAddr string // multi address denoting node's FQN (needed for deriving P2PBootstrappers in OCR), applicable only for bootstrap nodes + Labels map[string]string // labels to use when registering the node with job distributor } type DON struct { @@ -44,7 +44,7 @@ func (don *DON) PluginNodes() []Node { var pluginNodes []Node for _, node := range don.Nodes { for _, label := range node.labels { - if label.Key == NodeLabelKeyType && pointer.GetString(label.Value) == NodeLabelValuePlugin { + if label.Key == NodeLabelKeyType && value(label.Value) == NodeLabelValuePlugin { pluginNodes = append(pluginNodes, node) } } @@ -104,6 +104,12 @@ func NewRegisteredDON(ctx context.Context, nodeInfo []NodeInfo, jd JobDistributo return nil, fmt.Errorf("failed to create node %d: %w", i, err) } // node Labels so that it's easier to query them + for key, value := range info.Labels { + node.labels = append(node.labels, &ptypes.Label{ + Key: key, + Value: &value, + }) + } if info.IsBootstrap { // create multi address for OCR2, applicable only for bootstrap nodes if info.MultiAddr == "" { @@ -115,7 +121,7 @@ func NewRegisteredDON(ctx context.Context, nodeInfo []NodeInfo, jd JobDistributo node.adminAddr = "" node.labels = append(node.labels, &ptypes.Label{ Key: NodeLabelKeyType, - Value: pointer.ToString(NodeLabelValueBootstrap), + Value: ptr(NodeLabelValueBootstrap), }) } else { // multi address is not applicable for non-bootstrap nodes @@ -123,7 +129,7 @@ func NewRegisteredDON(ctx context.Context, nodeInfo []NodeInfo, jd JobDistributo node.multiAddr = "" node.labels = append(node.labels, &ptypes.Label{ Key: NodeLabelKeyType, - Value: pointer.ToString(NodeLabelValuePlugin), + Value: ptr(NodeLabelValuePlugin), }) } // Set up Job distributor in node and register node with the job distributor @@ -181,17 +187,35 @@ type JDChainConfigInput struct { func (n *Node) CreateCCIPOCRSupportedChains(ctx context.Context, chains []JDChainConfigInput, jd JobDistributor) error { for i, chain := range chains { chainId := strconv.FormatUint(chain.ChainID, 10) - accountAddr, err := n.gqlClient.FetchAccountAddress(ctx, chainId) - if err != nil { - return fmt.Errorf("failed to fetch account address for node %s: %w", n.Name, err) - } - if accountAddr == nil { - return fmt.Errorf("no account address found for node %s", n.Name) - } - if n.AccountAddr == nil { - n.AccountAddr = make(map[uint64]string) + var account string + switch chain.ChainType { + case "EVM": + accountAddr, err := n.gqlClient.FetchAccountAddress(ctx, chainId) + if err != nil { + return fmt.Errorf("failed to fetch account address for node %s: %w", n.Name, err) + } + if accountAddr == nil { + return fmt.Errorf("no account address found for node %s", n.Name) + } + if n.AccountAddr == nil { + n.AccountAddr = make(map[uint64]string) + } + n.AccountAddr[chain.ChainID] = *accountAddr + account = *accountAddr + case "APTOS", "SOLANA": + accounts, err := n.gqlClient.FetchKeys(ctx, chain.ChainType) + if err != nil { + return fmt.Errorf("failed to fetch account address for node %s: %w", n.Name, err) + } + if len(accounts) == 0 { + return fmt.Errorf("no account address found for node %s", n.Name) + } + + account = accounts[0] + default: + return fmt.Errorf("unsupported chainType %v", chain.ChainType) } - n.AccountAddr[chain.ChainID] = *accountAddr + peerID, err := n.gqlClient.FetchP2PPeerID(ctx) if err != nil { return fmt.Errorf("failed to fetch peer id for node %s: %w", n.Name, err) @@ -210,7 +234,7 @@ func (n *Node) CreateCCIPOCRSupportedChains(ctx context.Context, chains []JDChai // fetch node labels to know if the node is bootstrap or plugin isBootstrap := false for _, label := range n.labels { - if label.Key == NodeLabelKeyType && pointer.GetString(label.Value) == NodeLabelValueBootstrap { + if label.Key == NodeLabelKeyType && value(label.Value) == NodeLabelValueBootstrap { isBootstrap = true break } @@ -221,12 +245,12 @@ func (n *Node) CreateCCIPOCRSupportedChains(ctx context.Context, chains []JDChai JobDistributorID: n.JDId, ChainID: chainId, ChainType: chain.ChainType, - AccountAddr: pointer.GetString(accountAddr), + AccountAddr: account, AdminAddr: n.adminAddr, Ocr2Enabled: true, Ocr2IsBootstrap: isBootstrap, Ocr2Multiaddr: n.multiAddr, - Ocr2P2PPeerID: pointer.GetString(peerID), + Ocr2P2PPeerID: value(peerID), Ocr2KeyBundleID: ocr2BundleId, Ocr2Plugins: `{"commit":true,"execute":true,"median":false,"mercury":false}`, }) @@ -291,6 +315,20 @@ func (n *Node) RegisterNodeToJobDistributor(ctx context.Context, jd JobDistribut return fmt.Errorf("no csa key found for node %s", n.Name) } csaKey := strings.TrimPrefix(*csaKeyRes, "csa_") + + // tag nodes with p2p_id for easy lookup + peerID, err := n.gqlClient.FetchP2PPeerID(ctx) + if err != nil { + return fmt.Errorf("failed to fetch peer id for node %s: %w", n.Name, err) + } + if peerID == nil { + return fmt.Errorf("no peer id found for node %s", n.Name) + } + n.labels = append(n.labels, &ptypes.Label{ + Key: "p2p_id", + Value: peerID, + }) + // register the node in the job distributor registerResponse, err := jd.RegisterNode(ctx, &nodev1.RegisterNodeRequest{ PublicKey: csaKey, @@ -381,3 +419,15 @@ func (n *Node) ReplayLogs(blockByChain map[uint64]uint64) error { } return nil } + +func ptr[T any](v T) *T { + return &v +} + +func value[T any](v *T) T { + zero := new(T) + if v == nil { + return *zero + } + return *v +} diff --git a/deployment/environment/devenv/don_test.go b/deployment/environment/devenv/don_test.go new file mode 100644 index 00000000000..f93436f72f5 --- /dev/null +++ b/deployment/environment/devenv/don_test.go @@ -0,0 +1,19 @@ +package devenv + +import ( + "testing" + + "github.com/test-go/testify/require" +) + +func TestPtrVal(t *testing.T) { + + x := "hello" + xptr := ptr(x) + got := value(xptr) + require.Equal(t, x, got) + + var y *string + got = value(y) + require.Equal(t, "", got) +} diff --git a/deployment/environment/devenv/jd.go b/deployment/environment/devenv/jd.go index 2374aa1366c..9af8412d61e 100644 --- a/deployment/environment/devenv/jd.go +++ b/deployment/environment/devenv/jd.go @@ -4,8 +4,10 @@ import ( "context" "fmt" + "golang.org/x/oauth2" "google.golang.org/grpc" "google.golang.org/grpc/credentials" + "google.golang.org/grpc/metadata" csav1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/csa" jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" @@ -17,11 +19,39 @@ type JDConfig struct { GRPC string WSRPC string Creds credentials.TransportCredentials + Auth oauth2.TokenSource NodeInfo []NodeInfo } +func authTokenInterceptor(source oauth2.TokenSource) grpc.UnaryClientInterceptor { + return func( + ctx context.Context, + method string, + req, reply any, + cc *grpc.ClientConn, + invoker grpc.UnaryInvoker, + opts ...grpc.CallOption, + ) error { + token, err := source.Token() + if err != nil { + return err + } + + return invoker( + metadata.AppendToOutgoingContext(ctx, "authorization", "Bearer "+token.AccessToken), + method, req, reply, cc, opts..., + ) + } +} + func NewJDConnection(cfg JDConfig) (*grpc.ClientConn, error) { - conn, err := grpc.NewClient(cfg.GRPC, grpc.WithTransportCredentials(cfg.Creds)) + opts := []grpc.DialOption{ + grpc.WithTransportCredentials(cfg.Creds), + } + if cfg.Auth != nil { + opts = append(opts, grpc.WithUnaryInterceptor(authTokenInterceptor(cfg.Auth))) + } + conn, err := grpc.NewClient(cfg.GRPC, opts...) if err != nil { return nil, fmt.Errorf("failed to connect Job Distributor service. Err: %w", err) } diff --git a/deployment/environment/memory/chain.go b/deployment/environment/memory/chain.go index bad50be9b01..1bb359f9c53 100644 --- a/deployment/environment/memory/chain.go +++ b/deployment/environment/memory/chain.go @@ -71,7 +71,7 @@ func GenerateChainsWithIds(t *testing.T, chainIDs []uint64) map[uint64]EVMChain owner, err := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) require.NoError(t, err) backend := simulated.NewBackend(types.GenesisAlloc{ - owner.From: {Balance: big.NewInt(0).Mul(big.NewInt(100), big.NewInt(params.Ether))}}, + owner.From: {Balance: big.NewInt(0).Mul(big.NewInt(700000), big.NewInt(params.Ether))}}, simulated.WithBlockGasLimit(10000000)) backend.Commit() // Note initializes block timestamp to now(). chains[chainID] = EVMChain{ diff --git a/deployment/environment/memory/environment.go b/deployment/environment/memory/environment.go index 7b41a893f75..a1478a3bf52 100644 --- a/deployment/environment/memory/environment.go +++ b/deployment/environment/memory/environment.go @@ -5,6 +5,7 @@ import ( "fmt" "testing" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/core/types" "github.com/hashicorp/consul/sdk/freeport" "github.com/stretchr/testify/require" @@ -28,11 +29,23 @@ type MemoryEnvironmentConfig struct { RegistryConfig deployment.CapabilityRegistryConfig } +// For placeholders like aptos +func NewMemoryChain(t *testing.T, selector uint64) deployment.Chain { + return deployment.Chain{ + Selector: selector, + Client: nil, + DeployerKey: &bind.TransactOpts{}, + Confirm: func(tx *types.Transaction) (uint64, error) { + return 0, nil + }, + } +} + // Needed for environment variables on the node which point to prexisitng addresses. // i.e. CapReg. -func NewMemoryChains(t *testing.T, numChains int) (map[uint64]deployment.Chain, map[uint64]EVMChain) { +func NewMemoryChains(t *testing.T, numChains int) map[uint64]deployment.Chain { mchains := GenerateChains(t, numChains) - return generateMemoryChain(t, mchains), mchains + return generateMemoryChain(t, mchains) } func NewMemoryChainsWithChainIDs(t *testing.T, chainIDs []uint64) map[uint64]deployment.Chain { @@ -77,20 +90,20 @@ func generateMemoryChain(t *testing.T, inputs map[uint64]EVMChain) map[uint64]de return chains } -func NewNodes(t *testing.T, logLevel zapcore.Level, mchains map[uint64]EVMChain, numNodes, numBootstraps int, registryConfig deployment.CapabilityRegistryConfig) map[string]Node { +func NewNodes(t *testing.T, logLevel zapcore.Level, chains map[uint64]deployment.Chain, numNodes, numBootstraps int, registryConfig deployment.CapabilityRegistryConfig) map[string]Node { nodesByPeerID := make(map[string]Node) ports := freeport.GetN(t, numBootstraps+numNodes) // bootstrap nodes must be separate nodes from plugin nodes, // since we won't run a bootstrapper and a plugin oracle on the same // chainlink node in production. for i := 0; i < numBootstraps; i++ { - node := NewNode(t, ports[i], mchains, logLevel, true /* bootstrap */, registryConfig) + node := NewNode(t, ports[i], chains, logLevel, true /* bootstrap */, registryConfig) nodesByPeerID[node.Keys.PeerID.String()] = *node // Note in real env, this ID is allocated by JD. } for i := 0; i < numNodes; i++ { // grab port offset by numBootstraps, since above loop also takes some ports. - node := NewNode(t, ports[numBootstraps+i], mchains, logLevel, false /* bootstrap */, registryConfig) + node := NewNode(t, ports[numBootstraps+i], chains, logLevel, false /* bootstrap */, registryConfig) nodesByPeerID[node.Keys.PeerID.String()] = *node // Note in real env, this ID is allocated by JD. } @@ -117,8 +130,8 @@ func NewMemoryEnvironmentFromChainsNodes(t *testing.T, // To be used by tests and any kind of deployment logic. func NewMemoryEnvironment(t *testing.T, lggr logger.Logger, logLevel zapcore.Level, config MemoryEnvironmentConfig) deployment.Environment { - chains, mchains := NewMemoryChains(t, config.Chains) - nodes := NewNodes(t, logLevel, mchains, config.Nodes, config.Bootstraps, config.RegistryConfig) + chains := NewMemoryChains(t, config.Chains) + nodes := NewNodes(t, logLevel, chains, config.Nodes, config.Bootstraps, config.RegistryConfig) var nodeIDs []string for id := range nodes { nodeIDs = append(nodeIDs, id) diff --git a/deployment/environment/memory/job_client.go b/deployment/environment/memory/job_client.go index d572f5f92f5..df1e3d5c5d5 100644 --- a/deployment/environment/memory/job_client.go +++ b/deployment/environment/memory/job_client.go @@ -4,15 +4,21 @@ import ( "context" "errors" "fmt" + "slices" "strconv" + "strings" "github.com/ethereum/go-ethereum/common" "google.golang.org/grpc" + chainsel "github.com/smartcontractkit/chain-selectors" + csav1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/csa" jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" nodev1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node" + "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/shared/ptypes" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/validate" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" ) type JobClient struct { @@ -62,7 +68,7 @@ func (j JobClient) GetNode(ctx context.Context, in *nodev1.GetNodeRequest, opts return &nodev1.GetNodeResponse{ Node: &nodev1.Node{ Id: in.Id, - PublicKey: n.Keys.OCRKeyBundle.ID(), // is this the correct val? + PublicKey: n.Keys.CSA.PublicKeyString(), IsEnabled: true, IsConnected: true, }, @@ -71,35 +77,61 @@ func (j JobClient) GetNode(ctx context.Context, in *nodev1.GetNodeRequest, opts func (j JobClient) ListNodes(ctx context.Context, in *nodev1.ListNodesRequest, opts ...grpc.CallOption) (*nodev1.ListNodesResponse, error) { //TODO CCIP-3108 - var fiterIds map[string]struct{} - include := func(id string) bool { - if in.Filter == nil || len(in.Filter.Ids) == 0 { + include := func(node *nodev1.Node) bool { + if in.Filter == nil { return true } - // lazy init - if len(fiterIds) == 0 { - for _, id := range in.Filter.Ids { - fiterIds[id] = struct{}{} + if len(in.Filter.Ids) > 0 { + idx := slices.IndexFunc(in.Filter.Ids, func(id string) bool { + return node.Id == id + }) + if idx < 0 { + return false + } + } + for _, selector := range in.Filter.Selectors { + idx := slices.IndexFunc(node.Labels, func(label *ptypes.Label) bool { + return label.Key == selector.Key + }) + if idx < 0 { + return false + } + label := node.Labels[idx] + + switch selector.Op { + case ptypes.SelectorOp_IN: + values := strings.Split(*selector.Value, ",") + found := slices.Contains(values, *label.Value) + if !found { + return false + } + default: + panic("unimplemented selector") } } - _, ok := fiterIds[id] - return ok + return true } var nodes []*nodev1.Node for id, n := range j.Nodes { - if include(id) { - nodes = append(nodes, &nodev1.Node{ - Id: id, - PublicKey: n.Keys.OCRKeyBundle.ID(), // is this the correct val? - IsEnabled: true, - IsConnected: true, - }) + node := &nodev1.Node{ + Id: id, + PublicKey: n.Keys.CSA.ID(), + IsEnabled: true, + IsConnected: true, + Labels: []*ptypes.Label{ + { + Key: "p2p_id", + Value: ptr(n.Keys.PeerID.String()), + }, + }, + } + if include(node) { + nodes = append(nodes, node) } } return &nodev1.ListNodesResponse{ Nodes: nodes, }, nil - } func (j JobClient) ListNodeChainConfigs(ctx context.Context, in *nodev1.ListNodeChainConfigsRequest, opts ...grpc.CallOption) (*nodev1.ListNodeChainConfigsResponse, error) { @@ -113,8 +145,17 @@ func (j JobClient) ListNodeChainConfigs(ctx context.Context, in *nodev1.ListNode if !ok { return nil, fmt.Errorf("node id not found: %s", in.Filter.NodeIds[0]) } - offpk := n.Keys.OCRKeyBundle.OffchainPublicKey() - cpk := n.Keys.OCRKeyBundle.ConfigEncryptionPublicKey() + evmBundle := n.Keys.OCRKeyBundles[chaintype.EVM] + offpk := evmBundle.OffchainPublicKey() + cpk := evmBundle.ConfigEncryptionPublicKey() + + evmKeyBundle := &nodev1.OCR2Config_OCRKeyBundle{ + BundleId: evmBundle.ID(), + ConfigPublicKey: common.Bytes2Hex(cpk[:]), + OffchainPublicKey: common.Bytes2Hex(offpk[:]), + OnchainSigningAddress: evmBundle.OnChainPublicKey(), + } + var chainConfigs []*nodev1.ChainConfig for evmChainID, transmitter := range n.Keys.TransmittersByEVMChainID { chainConfigs = append(chainConfigs, &nodev1.ChainConfig{ @@ -123,7 +164,7 @@ func (j JobClient) ListNodeChainConfigs(ctx context.Context, in *nodev1.ListNode Type: nodev1.ChainType_CHAIN_TYPE_EVM, }, AccountAddress: transmitter.String(), - AdminAddress: "", + AdminAddress: transmitter.String(), // TODO: custom address Ocr1Config: nil, Ocr2Config: &nodev1.OCR2Config{ Enabled: true, @@ -131,19 +172,91 @@ func (j JobClient) ListNodeChainConfigs(ctx context.Context, in *nodev1.ListNode P2PKeyBundle: &nodev1.OCR2Config_P2PKeyBundle{ PeerId: n.Keys.PeerID.String(), }, - OcrKeyBundle: &nodev1.OCR2Config_OCRKeyBundle{ - BundleId: n.Keys.OCRKeyBundle.ID(), - ConfigPublicKey: common.Bytes2Hex(cpk[:]), - OffchainPublicKey: common.Bytes2Hex(offpk[:]), - OnchainSigningAddress: n.Keys.OCRKeyBundle.OnChainPublicKey(), - }, + OcrKeyBundle: evmKeyBundle, Multiaddr: n.Addr.String(), Plugins: nil, ForwarderAddress: ptr(""), }, }) } + for _, selector := range n.Chains { + family, err := chainsel.GetSelectorFamily(selector) + if err != nil { + return nil, err + } + chainID, err := chainsel.ChainIdFromSelector(selector) + if err != nil { + return nil, err + } + + if family == chainsel.FamilyEVM { + // already handled above + continue + } + + var ocrtype chaintype.ChainType + switch family { + case chainsel.FamilyEVM: + ocrtype = chaintype.EVM + case chainsel.FamilySolana: + ocrtype = chaintype.Solana + case chainsel.FamilyStarknet: + ocrtype = chaintype.StarkNet + case chainsel.FamilyCosmos: + ocrtype = chaintype.Cosmos + case chainsel.FamilyAptos: + ocrtype = chaintype.Aptos + default: + panic(fmt.Sprintf("Unsupported chain family %v", family)) + } + + bundle := n.Keys.OCRKeyBundles[ocrtype] + + offpk := bundle.OffchainPublicKey() + cpk := bundle.ConfigEncryptionPublicKey() + + keyBundle := &nodev1.OCR2Config_OCRKeyBundle{ + BundleId: bundle.ID(), + ConfigPublicKey: common.Bytes2Hex(cpk[:]), + OffchainPublicKey: common.Bytes2Hex(offpk[:]), + OnchainSigningAddress: bundle.OnChainPublicKey(), + } + + var ctype nodev1.ChainType + switch family { + case chainsel.FamilyEVM: + ctype = nodev1.ChainType_CHAIN_TYPE_EVM + case chainsel.FamilySolana: + ctype = nodev1.ChainType_CHAIN_TYPE_SOLANA + case chainsel.FamilyStarknet: + ctype = nodev1.ChainType_CHAIN_TYPE_STARKNET + case chainsel.FamilyAptos: + ctype = nodev1.ChainType_CHAIN_TYPE_APTOS + default: + panic(fmt.Sprintf("Unsupported chain family %v", family)) + } + chainConfigs = append(chainConfigs, &nodev1.ChainConfig{ + Chain: &nodev1.Chain{ + Id: strconv.Itoa(int(chainID)), + Type: ctype, + }, + AccountAddress: "", // TODO: support AccountAddress + AdminAddress: "", + Ocr1Config: nil, + Ocr2Config: &nodev1.OCR2Config{ + Enabled: true, + IsBootstrap: n.IsBoostrap, + P2PKeyBundle: &nodev1.OCR2Config_P2PKeyBundle{ + PeerId: n.Keys.PeerID.String(), + }, + OcrKeyBundle: keyBundle, + Multiaddr: n.Addr.String(), + Plugins: nil, + ForwarderAddress: ptr(""), + }, + }) + } // TODO: I think we can pull it from the feeds manager. return &nodev1.ListNodeChainConfigsResponse{ ChainConfigs: chainConfigs, diff --git a/deployment/environment/memory/node.go b/deployment/environment/memory/node.go index 90ad264faa9..c2e4e457fbd 100644 --- a/deployment/environment/memory/node.go +++ b/deployment/environment/memory/node.go @@ -15,6 +15,7 @@ import ( chainsel "github.com/smartcontractkit/chain-selectors" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" + "golang.org/x/exp/maps" "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/loop" @@ -35,6 +36,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/relay" @@ -46,6 +48,7 @@ import ( type Node struct { App chainlink.Application // Transmitter key/OCR keys for this node + Chains []uint64 // chain selectors Keys Keys Addr net.TCPAddr IsBoostrap bool @@ -68,11 +71,23 @@ func (n Node) ReplayLogs(chains map[uint64]uint64) error { func NewNode( t *testing.T, port int, // Port for the P2P V2 listener. - chains map[uint64]EVMChain, + chains map[uint64]deployment.Chain, logLevel zapcore.Level, bootstrap bool, registryConfig deployment.CapabilityRegistryConfig, ) *Node { + evmchains := make(map[uint64]EVMChain) + for _, chain := range chains { + evmChainID, err := chainsel.ChainIdFromSelector(chain.Selector) + if err != nil { + t.Fatal(err) + } + evmchains[evmChainID] = EVMChain{ + Backend: chain.Client.(*Backend).Sim, + DeployerKey: chain.DeployerKey, + } + } + // Do not want to load fixtures as they contain a dummy chainID. // Create database and initial configuration. cfg, db := heavyweight.FullTestDBNoFixturesV2(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -102,7 +117,7 @@ func NewNode( c.Log.Level = ptr(configv2.LogLevel(logLevel)) var chainConfigs v2toml.EVMConfigs - for chainID := range chains { + for chainID := range evmchains { chainConfigs = append(chainConfigs, createConfigV2Chain(chainID)) } c.EVM = chainConfigs @@ -114,7 +129,7 @@ func NewNode( // Create clients for the core node backed by sim. clients := make(map[uint64]client.Client) - for chainID, chain := range chains { + for chainID, chain := range evmchains { clients[chainID] = client.NewSimulatedBackendClient(t, chain.Backend, big.NewInt(int64(chainID))) } @@ -185,6 +200,7 @@ func NewNode( return &Node{ App: app, + Chains: maps.Keys(chains), Keys: keys, Addr: net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: port}, IsBoostrap: bootstrap, @@ -193,49 +209,86 @@ func NewNode( type Keys struct { PeerID p2pkey.PeerID + CSA csakey.KeyV2 TransmittersByEVMChainID map[uint64]common.Address - OCRKeyBundle ocr2key.KeyBundle + OCRKeyBundles map[chaintype.ChainType]ocr2key.KeyBundle } func CreateKeys(t *testing.T, - app chainlink.Application, chains map[uint64]EVMChain) Keys { + app chainlink.Application, chains map[uint64]deployment.Chain) Keys { ctx := tests.Context(t) _, err := app.GetKeyStore().P2P().Create(ctx) require.NoError(t, err) + err = app.GetKeyStore().CSA().EnsureKey(ctx) + require.NoError(t, err) + csaKeys, err := app.GetKeyStore().CSA().GetAll() + require.NoError(t, err) + csaKey := csaKeys[0] + p2pIDs, err := app.GetKeyStore().P2P().GetAll() require.NoError(t, err) require.Len(t, p2pIDs, 1) peerID := p2pIDs[0].PeerID() // create a transmitter for each chain transmitters := make(map[uint64]common.Address) - for chainID, chain := range chains { - cid := big.NewInt(int64(chainID)) + keybundles := make(map[chaintype.ChainType]ocr2key.KeyBundle) + for _, chain := range chains { + family, err := chainsel.GetSelectorFamily(chain.Selector) + require.NoError(t, err) + + var ctype chaintype.ChainType + switch family { + case chainsel.FamilyEVM: + ctype = chaintype.EVM + case chainsel.FamilySolana: + ctype = chaintype.Solana + case chainsel.FamilyStarknet: + ctype = chaintype.StarkNet + case chainsel.FamilyCosmos: + ctype = chaintype.Cosmos + case chainsel.FamilyAptos: + ctype = chaintype.Aptos + default: + panic(fmt.Sprintf("Unsupported chain family %v", family)) + } + + keybundle, err := app.GetKeyStore().OCR2().Create(ctx, ctype) + require.NoError(t, err) + keybundles[ctype] = keybundle + + if family != chainsel.FamilyEVM { + // TODO: only support EVM transmission keys for now + continue + } + + evmChainID, err := chainsel.ChainIdFromSelector(chain.Selector) + require.NoError(t, err) + + cid := big.NewInt(int64(evmChainID)) addrs, err2 := app.GetKeyStore().Eth().EnabledAddressesForChain(ctx, cid) require.NoError(t, err2) if len(addrs) == 1 { // just fund the address - fundAddress(t, chain.DeployerKey, addrs[0], assets.Ether(10).ToInt(), chain.Backend) - transmitters[chainID] = addrs[0] + transmitters[evmChainID] = addrs[0] } else { // create key and fund it _, err3 := app.GetKeyStore().Eth().Create(ctx, cid) - require.NoError(t, err3, "failed to create key for chain", chainID) + require.NoError(t, err3, "failed to create key for chain", evmChainID) sendingKeys, err3 := app.GetKeyStore().Eth().EnabledAddressesForChain(ctx, cid) require.NoError(t, err3) require.Len(t, sendingKeys, 1) - fundAddress(t, chain.DeployerKey, sendingKeys[0], assets.Ether(10).ToInt(), chain.Backend) - transmitters[chainID] = sendingKeys[0] + transmitters[evmChainID] = sendingKeys[0] } + backend := chain.Client.(*Backend).Sim + fundAddress(t, chain.DeployerKey, transmitters[evmChainID], assets.Ether(1000).ToInt(), backend) } - require.Len(t, transmitters, len(chains)) - keybundle, err := app.GetKeyStore().OCR2().Create(ctx, chaintype.EVM) - require.NoError(t, err) return Keys{ PeerID: peerID, + CSA: csaKey, TransmittersByEVMChainID: transmitters, - OCRKeyBundle: keybundle, + OCRKeyBundles: keybundles, } } diff --git a/deployment/environment/memory/node_test.go b/deployment/environment/memory/node_test.go index 9142f48bbfe..7cbcb66d04a 100644 --- a/deployment/environment/memory/node_test.go +++ b/deployment/environment/memory/node_test.go @@ -12,7 +12,7 @@ import ( ) func TestNode(t *testing.T) { - chains := GenerateChains(t, 3) + chains := NewMemoryChains(t, 3) ports := freeport.GetN(t, 1) node := NewNode(t, ports[0], chains, zapcore.DebugLevel, false, deployment.CapabilityRegistryConfig{}) // We expect 3 transmitter keys diff --git a/deployment/environment/memory/sim.go b/deployment/environment/memory/sim.go index 29ff89f1a1f..c0fba87e2b3 100644 --- a/deployment/environment/memory/sim.go +++ b/deployment/environment/memory/sim.go @@ -15,69 +15,69 @@ import ( // OnchainClient but also exposes backend methods. type Backend struct { mu sync.Mutex - sim *simulated.Backend + Sim *simulated.Backend } func (b *Backend) Commit() common.Hash { b.mu.Lock() defer b.mu.Unlock() - return b.sim.Commit() + return b.Sim.Commit() } func (b *Backend) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) { - return b.sim.Client().CodeAt(ctx, contract, blockNumber) + return b.Sim.Client().CodeAt(ctx, contract, blockNumber) } func (b *Backend) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { - return b.sim.Client().CallContract(ctx, call, blockNumber) + return b.Sim.Client().CallContract(ctx, call, blockNumber) } func (b *Backend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) { - return b.sim.Client().EstimateGas(ctx, call) + return b.Sim.Client().EstimateGas(ctx, call) } func (b *Backend) SuggestGasPrice(ctx context.Context) (*big.Int, error) { - return b.sim.Client().SuggestGasPrice(ctx) + return b.Sim.Client().SuggestGasPrice(ctx) } func (b *Backend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { - return b.sim.Client().SuggestGasTipCap(ctx) + return b.Sim.Client().SuggestGasTipCap(ctx) } func (b *Backend) SendTransaction(ctx context.Context, tx *types.Transaction) error { - return b.sim.Client().SendTransaction(ctx, tx) + return b.Sim.Client().SendTransaction(ctx, tx) } func (b *Backend) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { - return b.sim.Client().HeaderByNumber(ctx, number) + return b.Sim.Client().HeaderByNumber(ctx, number) } func (b *Backend) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { - return b.sim.Client().PendingCodeAt(ctx, account) + return b.Sim.Client().PendingCodeAt(ctx, account) } func (b *Backend) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { - return b.sim.Client().PendingNonceAt(ctx, account) + return b.Sim.Client().PendingNonceAt(ctx, account) } func (b *Backend) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]types.Log, error) { - return b.sim.Client().FilterLogs(ctx, q) + return b.Sim.Client().FilterLogs(ctx, q) } func (b *Backend) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { - return b.sim.Client().SubscribeFilterLogs(ctx, q, ch) + return b.Sim.Client().SubscribeFilterLogs(ctx, q, ch) } func (b *Backend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { - return b.sim.Client().TransactionReceipt(ctx, txHash) + return b.Sim.Client().TransactionReceipt(ctx, txHash) } func (b *Backend) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { - return b.sim.Client().BalanceAt(ctx, account, blockNumber) + return b.Sim.Client().BalanceAt(ctx, account, blockNumber) } func (b *Backend) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) { - return b.sim.Client().NonceAt(ctx, account, blockNumber) + return b.Sim.Client().NonceAt(ctx, account, blockNumber) } func NewBackend(sim *simulated.Backend) *Backend { @@ -85,6 +85,6 @@ func NewBackend(sim *simulated.Backend) *Backend { panic("simulated backend is nil") } return &Backend{ - sim: sim, + Sim: sim, } } diff --git a/deployment/environment/web/sdk/client/client.go b/deployment/environment/web/sdk/client/client.go index b22f52f3af4..011eb0cce31 100644 --- a/deployment/environment/web/sdk/client/client.go +++ b/deployment/environment/web/sdk/client/client.go @@ -7,7 +7,6 @@ import ( "net/http" "strings" - "github.com/AlekSi/pointer" "github.com/Khan/genqlient/graphql" "github.com/smartcontractkit/chainlink/deployment/environment/web/sdk/client/doer" @@ -18,6 +17,7 @@ type Client interface { FetchCSAPublicKey(ctx context.Context) (*string, error) FetchP2PPeerID(ctx context.Context) (*string, error) FetchAccountAddress(ctx context.Context, chainID string) (*string, error) + FetchKeys(ctx context.Context, chainType string) ([]string, error) FetchOCR2KeyBundleID(ctx context.Context, chainType string) (string, error) GetJob(ctx context.Context, id string) (*generated.GetJobResponse, error) ListJobs(ctx context.Context, offset, limit int) (*generated.ListJobsResponse, error) @@ -121,12 +121,38 @@ func (c *client) FetchAccountAddress(ctx context.Context, chainID string) (*stri } for _, keyDetail := range keys.EthKeys.GetResults() { if keyDetail.GetChain().Enabled && keyDetail.GetChain().Id == chainID { - return pointer.ToString(keyDetail.Address), nil + return &keyDetail.Address, nil } } return nil, fmt.Errorf("no account found for chain %s", chainID) } +func (c *client) FetchKeys(ctx context.Context, chainType string) ([]string, error) { + keys, err := generated.FetchKeys(ctx, c.gqlClient) + if err != nil { + return nil, err + } + if keys == nil { + return nil, fmt.Errorf("no accounts found") + } + switch generated.OCR2ChainType(chainType) { + case generated.OCR2ChainTypeAptos: + var accounts []string + for _, key := range keys.AptosKeys.GetResults() { + accounts = append(accounts, key.Account) + } + return accounts, nil + case generated.OCR2ChainTypeSolana: + var accounts []string + for _, key := range keys.SolanaKeys.GetResults() { + accounts = append(accounts, key.Id) + } + return accounts, nil + default: + return nil, fmt.Errorf("unsupported chainType %v", chainType) + } +} + func (c *client) GetJob(ctx context.Context, id string) (*generated.GetJobResponse, error) { return generated.GetJob(ctx, c.gqlClient, id) } diff --git a/deployment/environment/web/sdk/internal/generated/generated.go b/deployment/environment/web/sdk/internal/generated/generated.go index 68ab3e48e4f..7b16e4a1e3f 100644 --- a/deployment/environment/web/sdk/internal/generated/generated.go +++ b/deployment/environment/web/sdk/internal/generated/generated.go @@ -1887,6 +1887,58 @@ type FetchCSAKeysResponse struct { // GetCsaKeys returns FetchCSAKeysResponse.CsaKeys, and is useful for accessing the field via an interface. func (v *FetchCSAKeysResponse) GetCsaKeys() FetchCSAKeysCsaKeysCSAKeysPayload { return v.CsaKeys } +// FetchKeysAptosKeysAptosKeysPayload includes the requested fields of the GraphQL type AptosKeysPayload. +type FetchKeysAptosKeysAptosKeysPayload struct { + Results []FetchKeysAptosKeysAptosKeysPayloadResultsAptosKey `json:"results"` +} + +// GetResults returns FetchKeysAptosKeysAptosKeysPayload.Results, and is useful for accessing the field via an interface. +func (v *FetchKeysAptosKeysAptosKeysPayload) GetResults() []FetchKeysAptosKeysAptosKeysPayloadResultsAptosKey { + return v.Results +} + +// FetchKeysAptosKeysAptosKeysPayloadResultsAptosKey includes the requested fields of the GraphQL type AptosKey. +type FetchKeysAptosKeysAptosKeysPayloadResultsAptosKey struct { + Id string `json:"id"` + Account string `json:"account"` +} + +// GetId returns FetchKeysAptosKeysAptosKeysPayloadResultsAptosKey.Id, and is useful for accessing the field via an interface. +func (v *FetchKeysAptosKeysAptosKeysPayloadResultsAptosKey) GetId() string { return v.Id } + +// GetAccount returns FetchKeysAptosKeysAptosKeysPayloadResultsAptosKey.Account, and is useful for accessing the field via an interface. +func (v *FetchKeysAptosKeysAptosKeysPayloadResultsAptosKey) GetAccount() string { return v.Account } + +// FetchKeysResponse is returned by FetchKeys on success. +type FetchKeysResponse struct { + SolanaKeys FetchKeysSolanaKeysSolanaKeysPayload `json:"solanaKeys"` + AptosKeys FetchKeysAptosKeysAptosKeysPayload `json:"aptosKeys"` +} + +// GetSolanaKeys returns FetchKeysResponse.SolanaKeys, and is useful for accessing the field via an interface. +func (v *FetchKeysResponse) GetSolanaKeys() FetchKeysSolanaKeysSolanaKeysPayload { return v.SolanaKeys } + +// GetAptosKeys returns FetchKeysResponse.AptosKeys, and is useful for accessing the field via an interface. +func (v *FetchKeysResponse) GetAptosKeys() FetchKeysAptosKeysAptosKeysPayload { return v.AptosKeys } + +// FetchKeysSolanaKeysSolanaKeysPayload includes the requested fields of the GraphQL type SolanaKeysPayload. +type FetchKeysSolanaKeysSolanaKeysPayload struct { + Results []FetchKeysSolanaKeysSolanaKeysPayloadResultsSolanaKey `json:"results"` +} + +// GetResults returns FetchKeysSolanaKeysSolanaKeysPayload.Results, and is useful for accessing the field via an interface. +func (v *FetchKeysSolanaKeysSolanaKeysPayload) GetResults() []FetchKeysSolanaKeysSolanaKeysPayloadResultsSolanaKey { + return v.Results +} + +// FetchKeysSolanaKeysSolanaKeysPayloadResultsSolanaKey includes the requested fields of the GraphQL type SolanaKey. +type FetchKeysSolanaKeysSolanaKeysPayloadResultsSolanaKey struct { + Id string `json:"id"` +} + +// GetId returns FetchKeysSolanaKeysSolanaKeysPayloadResultsSolanaKey.Id, and is useful for accessing the field via an interface. +func (v *FetchKeysSolanaKeysSolanaKeysPayloadResultsSolanaKey) GetId() string { return v.Id } + // FetchOCR2KeyBundlesOcr2KeyBundlesOCR2KeyBundlesPayload includes the requested fields of the GraphQL type OCR2KeyBundlesPayload. type FetchOCR2KeyBundlesOcr2KeyBundlesOCR2KeyBundlesPayload struct { Results []FetchOCR2KeyBundlesOcr2KeyBundlesOCR2KeyBundlesPayloadResultsOCR2KeyBundle `json:"results"` @@ -5660,6 +5712,45 @@ func FetchCSAKeys( return &data_, err_ } +// The query or mutation executed by FetchKeys. +const FetchKeys_Operation = ` +query FetchKeys { + solanaKeys { + results { + id + } + } + aptosKeys { + results { + id + account + } + } +} +` + +func FetchKeys( + ctx_ context.Context, + client_ graphql.Client, +) (*FetchKeysResponse, error) { + req_ := &graphql.Request{ + OpName: "FetchKeys", + Query: FetchKeys_Operation, + } + var err_ error + + var data_ FetchKeysResponse + resp_ := &graphql.Response{Data: &data_} + + err_ = client_.MakeRequest( + ctx_, + req_, + resp_, + ) + + return &data_, err_ +} + // The query or mutation executed by FetchOCR2KeyBundles. const FetchOCR2KeyBundles_Operation = ` query FetchOCR2KeyBundles { diff --git a/deployment/environment/web/sdk/internal/genqlient.graphql b/deployment/environment/web/sdk/internal/genqlient.graphql index 06baf4f7913..4c998a4f6a6 100644 --- a/deployment/environment/web/sdk/internal/genqlient.graphql +++ b/deployment/environment/web/sdk/internal/genqlient.graphql @@ -45,6 +45,20 @@ query FetchAccounts { } } +query FetchKeys { + solanaKeys { + results { + id + } + } + aptosKeys { + results { + id + account + } + } +} + ##################### # ocr2KeyBundles ##################### @@ -456,4 +470,4 @@ mutation UpdateJobProposalSpecDefinition( code } } -} \ No newline at end of file +} diff --git a/deployment/go.mod b/deployment/go.mod index dbfb7e8472f..608f3493d92 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -6,7 +6,6 @@ go 1.22.8 replace github.com/smartcontractkit/chainlink/v2 => ../ require ( - github.com/AlekSi/pointer v1.1.0 github.com/Khan/genqlient v0.7.0 github.com/Masterminds/semver/v3 v3.3.0 github.com/avast/retry-go/v4 v4.6.0 @@ -35,6 +34,7 @@ require ( go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c + golang.org/x/oauth2 v0.23.0 golang.org/x/sync v0.8.0 google.golang.org/grpc v1.67.1 google.golang.org/protobuf v1.35.1 @@ -490,7 +490,6 @@ require ( golang.org/x/crypto v0.28.0 // indirect golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.30.0 // indirect - golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/term v0.25.0 // indirect golang.org/x/text v0.19.0 // indirect diff --git a/deployment/keystone/changeset/deploy_ocr3.go b/deployment/keystone/changeset/deploy_ocr3.go index 016eaa97d1f..e0edf4a4440 100644 --- a/deployment/keystone/changeset/deploy_ocr3.go +++ b/deployment/keystone/changeset/deploy_ocr3.go @@ -5,7 +5,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/deployment" - "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" kslib "github.com/smartcontractkit/chainlink/deployment/keystone" ) @@ -27,9 +26,8 @@ func DeployOCR3(env deployment.Environment, config interface{}) (deployment.Chan return deployment.ChangesetOutput{AddressBook: ab}, nil } -func ConfigureOCR3Contract(lggr logger.Logger, env deployment.Environment, ab deployment.AddressBook, registryChainSel uint64, nodes []*models.Node, cfg kslib.OracleConfigWithSecrets) (deployment.ChangesetOutput, error) { - - err := kslib.ConfigureOCR3ContractFromCLO(&env, registryChainSel, nodes, ab, &cfg) +func ConfigureOCR3Contract(lggr logger.Logger, env deployment.Environment, ab deployment.AddressBook, registryChainSel uint64, nodes []string, cfg kslib.OracleConfigWithSecrets) (deployment.ChangesetOutput, error) { + err := kslib.ConfigureOCR3ContractFromJD(&env, registryChainSel, nodes, ab, &cfg) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to configure OCR3Capability: %w", err) } diff --git a/deployment/keystone/changeset/internal/test/utils.go b/deployment/keystone/changeset/internal/test/utils.go index 9f332e8e28d..cea20fd327d 100644 --- a/deployment/keystone/changeset/internal/test/utils.go +++ b/deployment/keystone/changeset/internal/test/utils.go @@ -240,7 +240,7 @@ func (cc *CapabilityCache) AddCapabilities(lggr logger.Logger, chain deployment. } func testChain(t *testing.T) deployment.Chain { - chains, _ := memory.NewMemoryChains(t, 1) + chains := memory.NewMemoryChains(t, 1) var chain deployment.Chain for _, c := range chains { chain = c diff --git a/deployment/keystone/changeset/internal/update_don_test.go b/deployment/keystone/changeset/internal/update_don_test.go index baedda5e93d..12ccfe290b1 100644 --- a/deployment/keystone/changeset/internal/update_don_test.go +++ b/deployment/keystone/changeset/internal/update_don_test.go @@ -4,14 +4,14 @@ import ( "bytes" "math/big" "sort" - "strconv" "testing" "github.com/ethereum/go-ethereum/common" chainsel "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink-common/pkg/logger" + nodev1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node" "github.com/smartcontractkit/chainlink/deployment" - "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" + "github.com/smartcontractkit/chainlink/deployment/keystone" kslib "github.com/smartcontractkit/chainlink/deployment/keystone" kscs "github.com/smartcontractkit/chainlink/deployment/keystone/changeset" "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" @@ -95,18 +95,19 @@ func TestUpdateDon(t *testing.T) { t.Run("empty", func(t *testing.T) { cfg := setupUpdateDonTestConfig{ - dons: []kslib.DonCapabilities{ + dons: []kslib.DonInfo{ { - Name: "don 1", - Nops: []*models.NodeOperator{ - { - Name: "nop 1", - Nodes: []*models.Node{node_1, node_2, node_3, node_4}, - }, - }, + Name: "don 1", + Nodes: []keystone.Node{node_1, node_2, node_3, node_4}, Capabilities: []kcr.CapabilitiesRegistryCapability{cap_A}, }, }, + nops: []keystone.NOP{ + { + Name: "nop 1", + Nodes: []string{node_1.ID, node_2.ID, node_3.ID, node_4.ID}, + }, + }, } testCfg := setupUpdateDonTest(t, lggr, cfg) @@ -169,26 +170,24 @@ type minimalNodeCfg struct { admin common.Address } -func newNode(t *testing.T, cfg minimalNodeCfg) *models.Node { +func newNode(t *testing.T, cfg minimalNodeCfg) keystone.Node { t.Helper() - return &models.Node{ + return keystone.Node{ ID: cfg.id, PublicKey: &cfg.pubKey, - ChainConfigs: []*models.NodeChainConfig{ + ChainConfigs: []*nodev1.ChainConfig{ { - ID: "test chain", - Network: &models.Network{ - ID: "test network 1", - ChainID: strconv.FormatUint(cfg.registryChain.EvmChainID, 10), - ChainType: models.ChainTypeEvm, + Chain: &nodev1.Chain{ + Id: "test chain", + Type: nodev1.ChainType_CHAIN_TYPE_EVM, }, AdminAddress: cfg.admin.String(), - Ocr2Config: &models.NodeOCR2Config{ - P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ - PeerID: cfg.p2p.PeerID().String(), + Ocr2Config: &nodev1.OCR2Config{ + P2PKeyBundle: &nodev1.OCR2Config_P2PKeyBundle{ + PeerId: cfg.p2p.PeerID().String(), }, - OcrKeyBundle: &models.NodeOCR2ConfigOCRKeyBundle{ + OcrKeyBundle: &nodev1.OCR2Config_OCRKeyBundle{ OnchainSigningAddress: cfg.signingAddr, }, }, @@ -198,7 +197,8 @@ func newNode(t *testing.T, cfg minimalNodeCfg) *models.Node { } type setupUpdateDonTestConfig struct { - dons []kslib.DonCapabilities + dons []kslib.DonInfo + nops []keystone.NOP } type setupUpdateDonTestResult struct { @@ -208,28 +208,19 @@ type setupUpdateDonTestResult struct { func setupUpdateDonTest(t *testing.T, lggr logger.Logger, cfg setupUpdateDonTestConfig) *kstest.SetupTestRegistryResponse { t.Helper() - req := newSetupTestRegistryRequest(t, cfg.dons) + req := newSetupTestRegistryRequest(t, cfg.dons, cfg.nops) return kstest.SetupTestRegistry(t, lggr, req) } -func newSetupTestRegistryRequest(t *testing.T, dons []kslib.DonCapabilities) *kstest.SetupTestRegistryRequest { +func newSetupTestRegistryRequest(t *testing.T, dons []kslib.DonInfo, nops []keystone.NOP) *kstest.SetupTestRegistryRequest { t.Helper() - allNops := make(map[string]*models.NodeOperator) + nodes := make(map[string]keystone.Node) for _, don := range dons { - for _, nop := range don.Nops { - nop := nop - n, exists := allNops[nop.ID] - if exists { - nop.Nodes = append(n.Nodes, nop.Nodes...) - } - allNops[nop.ID] = nop + for _, node := range don.Nodes { + nodes[node.ID] = node } } - var nops []*models.NodeOperator - for _, nop := range allNops { - nops = append(nops, nop) - } - nopsToNodes := makeNopToNodes(t, nops) + nopsToNodes := makeNopToNodes(t, nops, nodes) testDons := makeTestDon(t, dons) p2pToCapabilities := makeP2PToCapabilities(t, dons) req := &kstest.SetupTestRegistryRequest{ @@ -240,46 +231,45 @@ func newSetupTestRegistryRequest(t *testing.T, dons []kslib.DonCapabilities) *ks return req } -func makeNopToNodes(t *testing.T, cloNops []*models.NodeOperator) map[kcr.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc { +func makeNopToNodes(t *testing.T, nops []keystone.NOP, nodes map[string]keystone.Node) map[kcr.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc { nopToNodes := make(map[kcr.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc) - for _, nop := range cloNops { + for _, nop := range nops { // all chain configs are the same wrt admin address & node keys // so we can just use the first one crnop := kcr.CapabilitiesRegistryNodeOperator{ Name: nop.Name, - Admin: common.HexToAddress(nop.Nodes[0].ChainConfigs[0].AdminAddress), + Admin: common.HexToAddress(nodes[nop.Nodes[0]].ChainConfigs[0].AdminAddress), } - var nodes []*internal.P2PSignerEnc - for _, node := range nop.Nodes { + var signers []*internal.P2PSignerEnc + for _, nodeID := range nop.Nodes { + node := nodes[nodeID] require.NotNil(t, node.PublicKey, "public key is nil %s", node.ID) // all chain configs are the same wrt admin address & node keys - p, err := kscs.NewP2PSignerEncFromCLO(node.ChainConfigs[0], *node.PublicKey) + p, err := kscs.NewP2PSignerEncFromJD(node.ChainConfigs[0], *node.PublicKey) require.NoError(t, err, "failed to make p2p signer enc from clo nod %s", node.ID) - nodes = append(nodes, p) + signers = append(signers, p) } - nopToNodes[crnop] = nodes + nopToNodes[crnop] = signers } return nopToNodes } -func makeP2PToCapabilities(t *testing.T, dons []kslib.DonCapabilities) map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability { +func makeP2PToCapabilities(t *testing.T, dons []kslib.DonInfo) map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability { p2pToCapabilities := make(map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability) for _, don := range dons { - for _, nop := range don.Nops { - for _, node := range nop.Nodes { - for _, cap := range don.Capabilities { - p, err := kscs.NewP2PSignerEncFromCLO(node.ChainConfigs[0], *node.PublicKey) - require.NoError(t, err, "failed to make p2p signer enc from clo nod %s", node.ID) - p2pToCapabilities[p.P2PKey] = append(p2pToCapabilities[p.P2PKey], cap) - } + for _, node := range don.Nodes { + for _, cap := range don.Capabilities { + p, err := kscs.NewP2PSignerEncFromJD(node.ChainConfigs[0], *node.PublicKey) + require.NoError(t, err, "failed to make p2p signer enc from clo nod %s", node.ID) + p2pToCapabilities[p.P2PKey] = append(p2pToCapabilities[p.P2PKey], cap) } } } return p2pToCapabilities } -func makeTestDon(t *testing.T, dons []kslib.DonCapabilities) []kstest.Don { +func makeTestDon(t *testing.T, dons []kslib.DonInfo) []kstest.Don { out := make([]kstest.Don, len(dons)) for i, don := range dons { out[i] = testDon(t, don) @@ -287,16 +277,14 @@ func makeTestDon(t *testing.T, dons []kslib.DonCapabilities) []kstest.Don { return out } -func testDon(t *testing.T, don kslib.DonCapabilities) kstest.Don { +func testDon(t *testing.T, don kslib.DonInfo) kstest.Don { var p2pids []p2pkey.PeerID - for _, nop := range don.Nops { - for _, node := range nop.Nodes { - // all chain configs are the same wrt admin address & node keys - // so we can just use the first one - p, err := kscs.NewP2PSignerEncFromCLO(node.ChainConfigs[0], *node.PublicKey) - require.NoError(t, err, "failed to make p2p signer enc from clo nod %s", node.ID) - p2pids = append(p2pids, p.P2PKey) - } + for _, node := range don.Nodes { + // all chain configs are the same wrt admin address & node keys + // so we can just use the first one + p, err := kscs.NewP2PSignerEncFromJD(node.ChainConfigs[0], *node.PublicKey) + require.NoError(t, err, "failed to make p2p signer enc from clo nod %s", node.ID) + p2pids = append(p2pids, p.P2PKey) } var capabilityConfigs []internal.CapabilityConfig diff --git a/deployment/keystone/changeset/internal/update_nodes_test.go b/deployment/keystone/changeset/internal/update_nodes_test.go index d764c4835c2..5488e5c761d 100644 --- a/deployment/keystone/changeset/internal/update_nodes_test.go +++ b/deployment/keystone/changeset/internal/update_nodes_test.go @@ -511,7 +511,7 @@ func testPeerID(t *testing.T, s string) p2pkey.PeerID { } func testChain(t *testing.T) deployment.Chain { - chains, _ := memory.NewMemoryChains(t, 1) + chains := memory.NewMemoryChains(t, 1) var chain deployment.Chain for _, c := range chains { chain = c diff --git a/deployment/keystone/changeset/types.go b/deployment/keystone/changeset/types.go index e8a86fa4272..fb609041792 100644 --- a/deployment/keystone/changeset/types.go +++ b/deployment/keystone/changeset/types.go @@ -6,24 +6,17 @@ import ( "fmt" v1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node" - "github.com/smartcontractkit/chainlink/deployment/environment/clo" - "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" ) -func NewP2PSignerEncFromCLO(cc *models.NodeChainConfig, pubkey string) (*P2PSignerEnc, error) { - ccfg := clo.NewChainConfig(cc) - var pubkeyB [32]byte - if _, err := hex.Decode(pubkeyB[:], []byte(pubkey)); err != nil { - return nil, fmt.Errorf("failed to decode pubkey %s: %w", pubkey, err) - } - return newP2PSignerEncFromJD(ccfg, pubkeyB) -} - -func newP2PSignerEncFromJD(ccfg *v1.ChainConfig, pubkey [32]byte) (*P2PSignerEnc, error) { +func NewP2PSignerEncFromJD(ccfg *v1.ChainConfig, pubkeyStr string) (*P2PSignerEnc, error) { if ccfg == nil { return nil, errors.New("nil ocr2config") } + var pubkey [32]byte + if _, err := hex.Decode(pubkey[:], []byte(pubkeyStr)); err != nil { + return nil, fmt.Errorf("failed to decode pubkey %s: %w", pubkey, err) + } ocfg := ccfg.Ocr2Config p2p := p2pkey.PeerID{} if err := p2p.UnmarshalString(ocfg.P2PKeyBundle.PeerId); err != nil { diff --git a/deployment/keystone/changeset/update_node_capabilities.go b/deployment/keystone/changeset/update_node_capabilities.go index 1d590d02831..0b6c4fb5462 100644 --- a/deployment/keystone/changeset/update_node_capabilities.go +++ b/deployment/keystone/changeset/update_node_capabilities.go @@ -7,7 +7,7 @@ import ( chainsel "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink/deployment" - "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" + "github.com/smartcontractkit/chainlink/deployment/keystone" kslib "github.com/smartcontractkit/chainlink/deployment/keystone" "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" @@ -19,7 +19,7 @@ var _ deployment.ChangeSet[*MutateNodeCapabilitiesRequest] = UpdateNodeCapabilit type P2PSignerEnc = internal.P2PSignerEnc -func NewP2PSignerEnc(n *models.Node, registryChainSel uint64) (*P2PSignerEnc, error) { +func NewP2PSignerEnc(n *keystone.Node, registryChainSel uint64) (*P2PSignerEnc, error) { p2p, signer, enc, err := kslib.ExtractKeys(n, registryChainSel) if err != nil { return nil, fmt.Errorf("failed to extract keys: %w", err) diff --git a/deployment/keystone/deploy.go b/deployment/keystone/deploy.go index f0231338ac3..a43f906178e 100644 --- a/deployment/keystone/deploy.go +++ b/deployment/keystone/deploy.go @@ -7,15 +7,18 @@ import ( "encoding/hex" "errors" "fmt" + "slices" "sort" "strings" "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/rpc" + "golang.org/x/exp/maps" + nodev1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node" + "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/shared/ptypes" "github.com/smartcontractkit/chainlink/deployment" - "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/durationpb" @@ -49,8 +52,10 @@ func (r ConfigureContractsRequest) Validate() error { if r.Env == nil { return errors.New("environment is nil") } - if len(r.Dons) == 0 { - return errors.New("no DONS") + for _, don := range r.Dons { + if err := don.Validate(); err != nil { + return fmt.Errorf("don validation failed for '%s': %w", don.Name, err) + } } _, ok := chainsel.ChainBySelector(r.RegistryChainSel) if !ok { @@ -90,8 +95,13 @@ func ConfigureContracts(ctx context.Context, lggr logger.Logger, req ConfigureCo return nil, fmt.Errorf("failed to configure registry: %w", err) } + donInfos, err := DonInfos(req.Dons, req.Env.Offchain) + if err != nil { + return nil, fmt.Errorf("failed to get don infos: %w", err) + } + // now we have the capability registry set up we need to configure the forwarder contracts and the OCR3 contract - dons, err := joinInfoAndNodes(cfgRegistryResp.DonInfos, req.Dons, req.RegistryChainSel) + dons, err := joinInfoAndNodes(cfgRegistryResp.DonInfos, donInfos, req.RegistryChainSel) if err != nil { return nil, fmt.Errorf("failed to assimilate registry to Dons: %w", err) } @@ -137,6 +147,101 @@ func DeployContracts(lggr logger.Logger, e *deployment.Environment, chainSel uin }, nil } +// DonInfo is DonCapabilities, but expanded to contain node information +type DonInfo struct { + Name string + Nodes []Node + Capabilities []kcr.CapabilitiesRegistryCapability // every capability is hosted on each node +} + +// TODO: merge with deployment/environment.go Node +type Node struct { + ID string + P2PID string + Name string + PublicKey *string + ChainConfigs []*nodev1.ChainConfig +} + +// TODO: merge with deployment/environment.go NodeInfo, we currently lookup based on p2p_id, and chain-selectors needs non-EVM support +func NodesFromJD(name string, nodeIDs []string, jd deployment.OffchainClient) ([]Node, error) { + // lookup nodes based on p2p_ids + var nodes []Node + selector := strings.Join(nodeIDs, ",") + nodesFromJD, err := jd.ListNodes(context.Background(), &nodev1.ListNodesRequest{ + Filter: &nodev1.ListNodesRequest_Filter{ + Enabled: 1, + Selectors: []*ptypes.Selector{ + { + Key: "p2p_id", + Op: ptypes.SelectorOp_IN, + Value: &selector, + }, + }, + }, + }) + if err != nil { + return nil, fmt.Errorf("failed to list nodes '%s': %w", name, err) + } + + for _, id := range nodeIDs { + idx := slices.IndexFunc(nodesFromJD.GetNodes(), func(node *nodev1.Node) bool { + return slices.ContainsFunc(node.Labels, func(label *ptypes.Label) bool { + return label.Key == "p2p_id" && *label.Value == id + }) + }) + if idx < 0 { + var got []string + for _, node := range nodesFromJD.GetNodes() { + for _, label := range node.Labels { + if label.Key == "p2p_id" { + got = append(got, *label.Value) + } + } + } + return nil, fmt.Errorf("node id %s not found in list '%s'", id, strings.Join(got, ",")) + } + + jdNode := nodesFromJD.Nodes[idx] + // TODO: Filter should accept multiple nodes + nodeChainConfigs, err := jd.ListNodeChainConfigs(context.Background(), &nodev1.ListNodeChainConfigsRequest{Filter: &nodev1.ListNodeChainConfigsRequest_Filter{ + NodeIds: []string{jdNode.Id}, // must use the jd-specific internal node id + }}) + if err != nil { + return nil, err + } + + nodes = append(nodes, Node{ + ID: jdNode.Id, + P2PID: id, + Name: name, + PublicKey: &jdNode.PublicKey, + ChainConfigs: nodeChainConfigs.GetChainConfigs(), + }) + } + return nodes, nil +} + +func DonInfos(dons []DonCapabilities, jd deployment.OffchainClient) ([]DonInfo, error) { + var donInfos []DonInfo + for _, don := range dons { + var nodeIDs []string + for _, nop := range don.Nops { + nodeIDs = append(nodeIDs, nop.Nodes...) + } + nodes, err := NodesFromJD(don.Name, nodeIDs, jd) + if err != nil { + return nil, err + } + donInfos = append(donInfos, DonInfo{ + Name: don.Name, + Nodes: nodes, + Capabilities: don.Capabilities, + }) + } + return donInfos, nil +} + // ConfigureRegistry configures the registry contract with the given DONS and their capabilities // the address book is required to contain the addresses of the deployed registry contract func ConfigureRegistry(ctx context.Context, lggr logger.Logger, req ConfigureContractsRequest, addrBook deployment.AddressBook) (*ConfigureContractsResponse, error) { @@ -153,6 +258,11 @@ func ConfigureRegistry(ctx context.Context, lggr logger.Logger, req ConfigureCon return nil, fmt.Errorf("failed to get contract sets: %w", err) } + donInfos, err := DonInfos(req.Dons, req.Env.Offchain) + if err != nil { + return nil, fmt.Errorf("failed to get don infos: %w", err) + } + // ensure registry is deployed and get the registry contract and chain var registry *kcr.CapabilitiesRegistry registryChainContracts, ok := contractSetsResp.ContractSets[req.RegistryChainSel] @@ -167,17 +277,17 @@ func ConfigureRegistry(ctx context.Context, lggr logger.Logger, req ConfigureCon // all the subsequent calls to the registry are in terms of nodes // compute the mapping of dons to their nodes for reuse in various registry calls - donToOcr2Nodes, err := mapDonsToNodes(req.Dons, true, req.RegistryChainSel) + donToOcr2Nodes, err := mapDonsToNodes(donInfos, true, req.RegistryChainSel) if err != nil { return nil, fmt.Errorf("failed to map dons to nodes: %w", err) } - // TODO: we can remove this abstractions and refactor the functions that accept them to accept []DonCapabilities + // TODO: we can remove this abstractions and refactor the functions that accept them to accept []DonInfos/DonCapabilities // they are unnecessary indirection - donToCapabilities := mapDonsToCaps(req.Dons) - nodeIdToNop, err := nodesToNops(req.Dons, req.RegistryChainSel) + donToCapabilities := mapDonsToCaps(donInfos) + nopsToNodeIDs, err := nopsToNodes(donInfos, req.Dons, req.RegistryChainSel) if err != nil { - return nil, fmt.Errorf("failed to map nodes to nops: %w", err) + return nil, fmt.Errorf("failed to map nops to nodes: %w", err) } // register capabilities @@ -192,14 +302,7 @@ func ConfigureRegistry(ctx context.Context, lggr logger.Logger, req ConfigureCon lggr.Infow("registered capabilities", "capabilities", capabilitiesResp.donToCapabilities) // register node operators - dedupedNops := make(map[kcr.CapabilitiesRegistryNodeOperator]struct{}) - var nopsList []kcr.CapabilitiesRegistryNodeOperator - for _, nop := range nodeIdToNop { - dedupedNops[nop] = struct{}{} - } - for nop := range dedupedNops { - nopsList = append(nopsList, nop) - } + nopsList := maps.Keys(nopsToNodeIDs) nopsResp, err := RegisterNOPS(ctx, lggr, RegisterNOPSRequest{ Chain: registryChain, Registry: registry, @@ -214,7 +317,7 @@ func ConfigureRegistry(ctx context.Context, lggr logger.Logger, req ConfigureCon nodesResp, err := registerNodes(lggr, ®isterNodesRequest{ registry: registry, chain: registryChain, - nodeIdToNop: nodeIdToNop, + nopToNodeIDs: nopsToNodeIDs, donToOcr2Nodes: donToOcr2Nodes, donToCapabilities: capabilitiesResp.donToCapabilities, nops: nopsResp.Nops, @@ -224,6 +327,8 @@ func ConfigureRegistry(ctx context.Context, lggr logger.Logger, req ConfigureCon } lggr.Infow("registered nodes", "nodes", nodesResp.nodeIDToParams) + // TODO: annotate nodes with node_operator_id in JD? + // register DONS donsResp, err := registerDons(lggr, registerDonsRequest{ registry: registry, @@ -318,7 +423,7 @@ func ConfigureOCR3Contract(env *deployment.Environment, chainSel uint64, dons [] return nil } -func ConfigureOCR3ContractFromCLO(env *deployment.Environment, chainSel uint64, nodes []*models.Node, addrBook deployment.AddressBook, cfg *OracleConfigWithSecrets) error { +func ConfigureOCR3ContractFromJD(env *deployment.Environment, chainSel uint64, nodeIDs []string, addrBook deployment.AddressBook, cfg *OracleConfigWithSecrets) error { registryChain, ok := env.Chains[chainSel] if !ok { return fmt.Errorf("chain %d not found in environment", chainSel) @@ -338,9 +443,13 @@ func ConfigureOCR3ContractFromCLO(env *deployment.Environment, chainSel uint64, if contract == nil { return fmt.Errorf("no ocr3 contract found for chain %d", chainSel) } + nodes, err := NodesFromJD("nodes", nodeIDs, env.Offchain) + if err != nil { + return err + } var ocr2nodes []*ocr2Node for _, node := range nodes { - n, err := newOcr2NodeFromClo(node, chainSel) + n, err := newOcr2NodeFromJD(&node, chainSel) if err != nil { return fmt.Errorf("failed to create ocr2 node from clo node: %w", err) } @@ -549,7 +658,7 @@ func DecodeErr(encodedABI string, err error) error { type registerNodesRequest struct { registry *kcr.CapabilitiesRegistry chain deployment.Chain - nodeIdToNop map[string]kcr.CapabilitiesRegistryNodeOperator + nopToNodeIDs map[kcr.CapabilitiesRegistryNodeOperator][]string donToOcr2Nodes map[string][]*ocr2Node donToCapabilities map[string][]RegisteredCapability nops []*kcr.CapabilitiesRegistryNodeOperatorAdded @@ -562,21 +671,18 @@ type registerNodesResponse struct { // can sign the transactions update the contract state // TODO: 467 refactor to support MCMS. Specifically need to separate the call data generation from the actual contract call func registerNodes(lggr logger.Logger, req *registerNodesRequest) (*registerNodesResponse, error) { - lggr.Infow("registering nodes...", "len", len(req.nodeIdToNop)) - nopToNodeIDs := make(map[kcr.CapabilitiesRegistryNodeOperator][]string) - for nodeID, nop := range req.nodeIdToNop { - if _, ok := nopToNodeIDs[nop]; !ok { - nopToNodeIDs[nop] = make([]string, 0) - } - nopToNodeIDs[nop] = append(nopToNodeIDs[nop], nodeID) + var count int + for _, nodes := range req.nopToNodeIDs { + count += len(nodes) } + lggr.Infow("registering nodes...", "len", count) nodeToRegisterNop := make(map[string]*kcr.CapabilitiesRegistryNodeOperatorAdded) for _, nop := range req.nops { n := kcr.CapabilitiesRegistryNodeOperator{ Name: nop.Name, Admin: nop.Admin, } - nodeIDs := nopToNodeIDs[n] + nodeIDs := req.nopToNodeIDs[n] for _, nodeID := range nodeIDs { _, exists := nodeToRegisterNop[nodeID] if !exists { diff --git a/deployment/keystone/deploy_test.go b/deployment/keystone/deploy_test.go index 96350a91d6c..4e0d2a52dcc 100644 --- a/deployment/keystone/deploy_test.go +++ b/deployment/keystone/deploy_test.go @@ -4,11 +4,14 @@ import ( "encoding/json" "fmt" "os" + "strconv" "testing" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/stretchr/testify/assert" "github.com/test-go/testify/require" + "go.uber.org/zap/zapcore" + "golang.org/x/exp/maps" chainsel "github.com/smartcontractkit/chain-selectors" @@ -17,6 +20,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/environment/clo" "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" + "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/deployment/keystone" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -25,6 +29,204 @@ import ( func TestDeploy(t *testing.T) { lggr := logger.TestLogger(t) + // sepolia; all nodes are on the this chain + sepoliaChainId := uint64(11155111) + sepoliaArbitrumChainId := uint64(421614) + + sepoliaChainSel, err := chainsel.SelectorFromChainId(sepoliaChainId) + require.NoError(t, err) + // sepoliaArbitrumChainSel, err := chainsel.SelectorFromChainId(sepoliaArbitrumChainId) + // require.NoError(t, err) + // aptosChainSel := uint64(999) // TODO: + + crConfig := deployment.CapabilityRegistryConfig{ + EVMChainID: sepoliaChainId, + Contract: [20]byte{}, + } + + evmChains := memory.NewMemoryChainsWithChainIDs(t, []uint64{sepoliaChainId, sepoliaArbitrumChainId}) + // aptosChain := memory.NewMemoryChain(t, aptosChainSel) + + wfChains := map[uint64]deployment.Chain{} + wfChains[sepoliaChainSel] = evmChains[sepoliaChainSel] + // wfChains[aptosChainSel] = aptosChain + wfNodes := memory.NewNodes(t, zapcore.InfoLevel, wfChains, 4, 0, crConfig) + require.Len(t, wfNodes, 4) + + cwNodes := memory.NewNodes(t, zapcore.InfoLevel, evmChains, 4, 0, crConfig) + + assetChains := map[uint64]deployment.Chain{} + assetChains[sepoliaChainSel] = evmChains[sepoliaChainSel] + assetNodes := memory.NewNodes(t, zapcore.InfoLevel, assetChains, 4, 0, crConfig) + require.Len(t, assetNodes, 4) + + // TODO: partition nodes into multiple nops + + wfDon := keystone.DonCapabilities{ + Name: keystone.WFDonName, + Nops: []keystone.NOP{ + { + Name: "nop 1", + Nodes: maps.Keys(wfNodes), + }, + }, + Capabilities: []kcr.CapabilitiesRegistryCapability{keystone.OCR3Cap}, + } + cwDon := keystone.DonCapabilities{ + Name: keystone.TargetDonName, + Nops: []keystone.NOP{ + { + Name: "nop 2", + Nodes: maps.Keys(cwNodes), + }, + }, + Capabilities: []kcr.CapabilitiesRegistryCapability{keystone.WriteChainCap}, + } + assetDon := keystone.DonCapabilities{ + Name: keystone.StreamDonName, + Nops: []keystone.NOP{ + { + Name: "nop 3", + Nodes: maps.Keys(assetNodes), + }, + }, + Capabilities: []kcr.CapabilitiesRegistryCapability{keystone.StreamTriggerCap}, + } + + allChains := make(map[uint64]deployment.Chain) + maps.Copy(allChains, evmChains) + // allChains[aptosChainSel] = aptosChain + + allNodes := make(map[string]memory.Node) + maps.Copy(allNodes, wfNodes) + maps.Copy(allNodes, cwNodes) + maps.Copy(allNodes, assetNodes) + env := memory.NewMemoryEnvironmentFromChainsNodes(t, lggr, allChains, allNodes) + + var ocr3Config = keystone.OracleConfigWithSecrets{ + OracleConfig: keystone.OracleConfig{ + MaxFaultyOracles: len(wfNodes) / 3, + }, + OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), + } + + ctx := tests.Context(t) + // explicitly deploy the contracts + cs, err := keystone.DeployContracts(lggr, &env, sepoliaChainSel) + require.NoError(t, err) + env.ExistingAddresses = cs.AddressBook + deployReq := keystone.ConfigureContractsRequest{ + RegistryChainSel: sepoliaChainSel, + Env: &env, + OCR3Config: &ocr3Config, + Dons: []keystone.DonCapabilities{wfDon, cwDon, assetDon}, + DoContractDeploy: false, + } + deployResp, err := keystone.ConfigureContracts(ctx, lggr, deployReq) + require.NoError(t, err) + ad := deployResp.Changeset.AddressBook + addrs, err := ad.Addresses() + require.NoError(t, err) + lggr.Infow("Deployed Keystone contracts", "address book", addrs) + + // all contracts on home chain + homeChainAddrs, err := ad.AddressesForChain(sepoliaChainSel) + require.NoError(t, err) + require.Len(t, homeChainAddrs, 3) + // only forwarder on non-home chain + for sel := range env.Chains { + chainAddrs, err := ad.AddressesForChain(sel) + require.NoError(t, err) + if sel != sepoliaChainSel { + require.Len(t, chainAddrs, 1) + } else { + require.Len(t, chainAddrs, 3) + } + containsForwarder := false + for _, tv := range chainAddrs { + if tv.Type == keystone.KeystoneForwarder { + containsForwarder = true + break + } + } + require.True(t, containsForwarder, "no forwarder found in %v on chain %d for target don", chainAddrs, sel) + } + req := &keystone.GetContractSetsRequest{ + Chains: env.Chains, + AddressBook: ad, + } + + contractSetsResp, err := keystone.GetContractSets(lggr, req) + require.NoError(t, err) + require.Len(t, contractSetsResp.ContractSets, len(env.Chains)) + // check the registry + regChainContracts, ok := contractSetsResp.ContractSets[sepoliaChainSel] + require.True(t, ok) + gotRegistry := regChainContracts.CapabilitiesRegistry + require.NotNil(t, gotRegistry) + // contract reads + gotDons, err := gotRegistry.GetDONs(&bind.CallOpts{}) + if err != nil { + err = keystone.DecodeErr(kcr.CapabilitiesRegistryABI, err) + require.Fail(t, fmt.Sprintf("failed to get Dons from registry at %s: %s", gotRegistry.Address().String(), err)) + } + require.NoError(t, err) + assert.Len(t, gotDons, len(deployReq.Dons)) + + for n, info := range deployResp.DonInfos { + found := false + for _, gdon := range gotDons { + if gdon.Id == info.Id { + found = true + assert.EqualValues(t, info, gdon) + break + } + } + require.True(t, found, "don %s not found in registry", n) + } + // check the forwarder + for _, cs := range contractSetsResp.ContractSets { + forwarder := cs.Forwarder + require.NotNil(t, forwarder) + // any read to ensure that the contract is deployed correctly + _, err := forwarder.Owner(&bind.CallOpts{}) + require.NoError(t, err) + // TODO expand this test; there is no get method on the forwarder so unclear how to test it + } + // check the ocr3 contract + for chainSel, cs := range contractSetsResp.ContractSets { + if chainSel != sepoliaChainSel { + require.Nil(t, cs.OCR3) + continue + } + require.NotNil(t, cs.OCR3) + // any read to ensure that the contract is deployed correctly + _, err := cs.OCR3.LatestConfigDetails(&bind.CallOpts{}) + require.NoError(t, err) + } +} + +// TODO: Deprecated, remove everything below that leverages CLO + +func nodeOperatorsToIDs(t *testing.T, nops []*models.NodeOperator) (nodeIDs []keystone.NOP) { + for _, nop := range nops { + nodeOperator := keystone.NOP{ + Name: nop.Name, + } + for _, node := range nop.Nodes { + p2pID, err := clo.NodeP2PId(node) + require.NoError(t, err) + + nodeOperator.Nodes = append(nodeOperator.Nodes, p2pID) + } + nodeIDs = append(nodeIDs, nodeOperator) + } + return nodeIDs +} + +func TestDeployCLO(t *testing.T) { + lggr := logger.TestLogger(t) + wfNops := loadTestNops(t, "testdata/workflow_nodes.json") cwNops := loadTestNops(t, "testdata/chain_writer_nodes.json") assetNops := loadTestNops(t, "testdata/asset_nodes.json") @@ -35,23 +237,65 @@ func TestDeploy(t *testing.T) { require.Len(t, assetNops, 16) requireChains(t, assetNops, []models.ChainType{models.ChainTypeEvm}) + wfNodes := nodeOperatorsToIDs(t, wfNops) + cwNodes := nodeOperatorsToIDs(t, cwNops) + assetNodes := nodeOperatorsToIDs(t, assetNops) + wfDon := keystone.DonCapabilities{ Name: keystone.WFDonName, - Nops: wfNops, + Nops: wfNodes, Capabilities: []kcr.CapabilitiesRegistryCapability{keystone.OCR3Cap}, } cwDon := keystone.DonCapabilities{ Name: keystone.TargetDonName, - Nops: cwNops, + Nops: cwNodes, Capabilities: []kcr.CapabilitiesRegistryCapability{keystone.WriteChainCap}, } assetDon := keystone.DonCapabilities{ Name: keystone.StreamDonName, - Nops: assetNops, + Nops: assetNodes, Capabilities: []kcr.CapabilitiesRegistryCapability{keystone.StreamTriggerCap}, } - env := makeMultiDonTestEnv(t, lggr, []keystone.DonCapabilities{wfDon, cwDon, assetDon}) + var allNops []*models.NodeOperator + allNops = append(allNops, wfNops...) + allNops = append(allNops, cwNops...) + allNops = append(allNops, assetNops...) + + chains := make(map[uint64]struct{}) + for _, nop := range allNops { + for _, node := range nop.Nodes { + for _, chain := range node.ChainConfigs { + // chain selector lib doesn't support chain id 2 and we don't use it in tests + // because it's not an evm chain + if chain.Network.ChainID == "2" { // aptos chain + continue + } + id, err := strconv.ParseUint(chain.Network.ChainID, 10, 64) + require.NoError(t, err, "failed to parse chain id to uint64") + chains[id] = struct{}{} + } + } + } + var chainIDs []uint64 + for c := range chains { + chainIDs = append(chainIDs, c) + } + allChains := memory.NewMemoryChainsWithChainIDs(t, chainIDs) + + env := &deployment.Environment{ + Name: "CLO", + ExistingAddresses: deployment.NewMemoryAddressBook(), + Offchain: clo.NewJobClient(lggr, clo.JobClientConfig{Nops: allNops}), + Chains: allChains, + Logger: lggr, + } + // assume that all the nodes in the provided input nops are part of the don + for _, nop := range allNops { + for _, node := range nop.Nodes { + env.NodeIDs = append(env.NodeIDs, node.ID) + } + } // sepolia; all nodes are on the this chain registryChainSel, err := chainsel.SelectorFromChainId(11155111) @@ -186,25 +430,6 @@ func requireChains(t *testing.T, donNops []*models.NodeOperator, cs []models.Cha } } -func makeMultiDonTestEnv(t *testing.T, lggr logger.Logger, dons []keystone.DonCapabilities) *deployment.Environment { - var donToEnv = make(map[string]*deployment.Environment) - // chain selector lib doesn't support chain id 2 and we don't use it in tests - // because it's not an evm chain - ignoreAptos := func(c *models.NodeChainConfig) bool { - return c.Network.ChainID == "2" // aptos chain - } - for _, don := range dons { - env := clo.NewDonEnvWithMemoryChains(t, clo.DonEnvConfig{ - DonName: don.Name, - Nops: don.Nops, - Logger: lggr, - }, ignoreAptos) - donToEnv[don.Name] = env - } - menv := clo.NewTestEnv(t, lggr, donToEnv) - return menv.Flatten("testing-env") -} - func loadTestNops(t *testing.T, pth string) []*models.NodeOperator { f, err := os.ReadFile(pth) require.NoError(t, err) diff --git a/deployment/keystone/types.go b/deployment/keystone/types.go index e01ec6d0d55..e5657657ed9 100644 --- a/deployment/keystone/types.go +++ b/deployment/keystone/types.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "errors" "fmt" + "slices" "sort" "strconv" "strings" @@ -13,7 +14,6 @@ import ( chainsel "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink/deployment" - "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" v1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node" @@ -100,8 +100,7 @@ func (o *ocr2Node) toNodeKeys() NodeKeys { AptosOnchainPublicKey: aptosOnchainPublicKey, } } - -func newOcr2NodeFromClo(n *models.Node, registryChainSel uint64) (*ocr2Node, error) { +func newOcr2NodeFromJD(n *Node, registryChainSel uint64) (*ocr2Node, error) { if n.PublicKey == nil { return nil, errors.New("no public key") } @@ -110,22 +109,22 @@ func newOcr2NodeFromClo(n *models.Node, registryChainSel uint64) (*ocr2Node, err return nil, errors.New("no chain configs") } // all nodes should have an evm chain config, specifically the registry chain - evmCC, err := registryChainConfig(n.ChainConfigs, chaintype.EVM, registryChainSel) + evmCC, err := registryChainConfig(n.ChainConfigs, v1.ChainType_CHAIN_TYPE_EVM, registryChainSel) if err != nil { return nil, fmt.Errorf("failed to get registry chain config for sel %d: %w", registryChainSel, err) } cfgs := map[chaintype.ChainType]*v1.ChainConfig{ chaintype.EVM: evmCC, } - aptosCC, exists := firstChainConfigByType(n.ChainConfigs, chaintype.Aptos) + aptosCC, exists := firstChainConfigByType(n.ChainConfigs, v1.ChainType_CHAIN_TYPE_APTOS) if exists { cfgs[chaintype.Aptos] = aptosCC } return newOcr2Node(n.ID, cfgs, *n.PublicKey) } -func ExtractKeys(n *models.Node, registerChainSel uint64) (p2p p2pkey.PeerID, signer [32]byte, encPubKey [32]byte, err error) { - orc2n, err := newOcr2NodeFromClo(n, registerChainSel) +func ExtractKeys(n *Node, registerChainSel uint64) (p2p p2pkey.PeerID, signer [32]byte, encPubKey [32]byte, err error) { + orc2n, err := newOcr2NodeFromJD(n, registerChainSel) if err != nil { return p2p, signer, encPubKey, fmt.Errorf("failed to create ocr2 node for node %s: %w", n.ID, err) } @@ -201,28 +200,52 @@ func makeNodeKeysSlice(nodes []*ocr2Node) []NodeKeys { return out } +type NOP struct { + Name string + Nodes []string // peerID +} + +func (v NOP) Validate() error { + if v.Name == "" { + return errors.New("name is empty") + } + if len(v.Nodes) == 0 { + return errors.New("no nodes") + } + for i, n := range v.Nodes { + _, err := p2pkey.MakePeerID(n) + if err != nil { + return fmt.Errorf("failed to nop %s: node %d is not valid peer id %s: %w", v.Name, i, n, err) + } + } + + return nil +} + // DonCapabilities is a set of capabilities hosted by a set of node operators // in is in a convenient form to handle the CLO representation of the nop data type DonCapabilities struct { Name string - Nops []*models.NodeOperator // each nop is a node operator and may have multiple nodes + Nops []NOP Capabilities []kcr.CapabilitiesRegistryCapability // every capability is hosted on each nop } -// map the node id to the NOP -func (dc DonCapabilities) nopsByNodeID(chainSelector uint64) (map[string]capabilities_registry.CapabilitiesRegistryNodeOperator, error) { - out := make(map[string]capabilities_registry.CapabilitiesRegistryNodeOperator) - for _, nop := range dc.Nops { - for _, node := range nop.Nodes { - a, err := AdminAddress(node, chainSelector) - if err != nil { - return nil, fmt.Errorf("failed to get admin address for node %s: %w", node.ID, err) - } - out[node.ID] = NodeOperator(nop.Name, a) - +func (v DonCapabilities) Validate() error { + if v.Name == "" { + return errors.New("name is empty") + } + if len(v.Nops) == 0 { + return errors.New("no nops") + } + for i, n := range v.Nops { + if err := n.Validate(); err != nil { + return fmt.Errorf("failed to validate nop %d '%s': %w", i, n.Name, err) } } - return out, nil + if len(v.Capabilities) == 0 { + return errors.New("no capabilities") + } + return nil } func NodeOperator(name string, adminAddress string) capabilities_registry.CapabilitiesRegistryNodeOperator { @@ -232,42 +255,63 @@ func NodeOperator(name string, adminAddress string) capabilities_registry.Capabi } } -func AdminAddress(n *models.Node, chainSel uint64) (string, error) { +func AdminAddress(n *Node, chainSel uint64) (string, error) { cid, err := chainsel.ChainIdFromSelector(chainSel) if err != nil { return "", fmt.Errorf("failed to get chain id from selector %d: %w", chainSel, err) } cidStr := strconv.FormatUint(cid, 10) for _, chain := range n.ChainConfigs { - if chain.Network.ChainID == cidStr { + //TODO validate chainType field + if chain.Chain.Id == cidStr { return chain.AdminAddress, nil } } return "", fmt.Errorf("no chain config for chain %d", cid) } -// helpers to maintain compatibility with the existing registration functions -// nodesToNops converts a list of DonCapabilities to a map of node id to NOP -func nodesToNops(dons []DonCapabilities, chainSel uint64) (map[string]capabilities_registry.CapabilitiesRegistryNodeOperator, error) { - out := make(map[string]capabilities_registry.CapabilitiesRegistryNodeOperator) +func nopsToNodes(donInfos []DonInfo, dons []DonCapabilities, chainSelector uint64) (map[capabilities_registry.CapabilitiesRegistryNodeOperator][]string, error) { + out := make(map[capabilities_registry.CapabilitiesRegistryNodeOperator][]string) for _, don := range dons { - nops, err := don.nopsByNodeID(chainSel) - if err != nil { - return nil, fmt.Errorf("failed to get registry NOPs for don %s: %w", don.Name, err) - } - for donName, nop := range nops { - _, exists := out[donName] - if exists { - continue + for _, nop := range don.Nops { + idx := slices.IndexFunc(donInfos, func(donInfo DonInfo) bool { + return donInfo.Name == don.Name + }) + if idx < 0 { + return nil, fmt.Errorf("couldn't find donInfo for %v", don.Name) + } + donInfo := donInfos[idx] + idx = slices.IndexFunc(donInfo.Nodes, func(node Node) bool { + return node.P2PID == nop.Nodes[0] + }) + if idx < 0 { + return nil, fmt.Errorf("couldn't find node with p2p_id %v", nop.Nodes[0]) + } + node := donInfo.Nodes[idx] + a, err := AdminAddress(&node, chainSelector) + if err != nil { + return nil, fmt.Errorf("failed to get admin address for node %s: %w", node.ID, err) + } + nodeOperator := NodeOperator(nop.Name, a) + for _, node := range nop.Nodes { + + idx = slices.IndexFunc(donInfo.Nodes, func(n Node) bool { + return n.P2PID == node + }) + if idx < 0 { + return nil, fmt.Errorf("couldn't find node with p2p_id %v", node) + } + out[nodeOperator] = append(out[nodeOperator], donInfo.Nodes[idx].ID) + } - out[donName] = nop } } + return out, nil } // mapDonsToCaps converts a list of DonCapabilities to a map of don name to capabilities -func mapDonsToCaps(dons []DonCapabilities) map[string][]kcr.CapabilitiesRegistryCapability { +func mapDonsToCaps(dons []DonInfo) map[string][]kcr.CapabilitiesRegistryCapability { out := make(map[string][]kcr.CapabilitiesRegistryCapability) for _, don := range dons { out[don.Name] = don.Capabilities @@ -277,53 +321,48 @@ func mapDonsToCaps(dons []DonCapabilities) map[string][]kcr.CapabilitiesRegistry // mapDonsToNodes returns a map of don name to simplified representation of their nodes // all nodes must have evm config and ocr3 capability nodes are must also have an aptos chain config -func mapDonsToNodes(dons []DonCapabilities, excludeBootstraps bool, registryChainSel uint64) (map[string][]*ocr2Node, error) { +func mapDonsToNodes(dons []DonInfo, excludeBootstraps bool, registryChainSel uint64) (map[string][]*ocr2Node, error) { donToOcr2Nodes := make(map[string][]*ocr2Node) // get the nodes for each don from the offchain client, get ocr2 config from one of the chain configs for the node b/c // they are equivalent, and transform to ocr2node representation for _, don := range dons { - for _, nop := range don.Nops { - for _, node := range nop.Nodes { - ocr2n, err := newOcr2NodeFromClo(node, registryChainSel) - if err != nil { - return nil, fmt.Errorf("failed to create ocr2 node for node %s: %w", node.ID, err) - } - if excludeBootstraps && ocr2n.IsBoostrap { - continue - } - if _, ok := donToOcr2Nodes[don.Name]; !ok { - donToOcr2Nodes[don.Name] = make([]*ocr2Node, 0) - } - donToOcr2Nodes[don.Name] = append(donToOcr2Nodes[don.Name], ocr2n) - + for _, node := range don.Nodes { + ocr2n, err := newOcr2NodeFromJD(&node, registryChainSel) + if err != nil { + return nil, fmt.Errorf("failed to create ocr2 node for node %s: %w", node.ID, err) } + if excludeBootstraps && ocr2n.IsBoostrap { + continue + } + if _, ok := donToOcr2Nodes[don.Name]; !ok { + donToOcr2Nodes[don.Name] = make([]*ocr2Node, 0) + } + donToOcr2Nodes[don.Name] = append(donToOcr2Nodes[don.Name], ocr2n) } } return donToOcr2Nodes, nil } -func firstChainConfigByType(ccfgs []*models.NodeChainConfig, t chaintype.ChainType) (*v1.ChainConfig, bool) { +func firstChainConfigByType(ccfgs []*v1.ChainConfig, t v1.ChainType) (*v1.ChainConfig, bool) { for _, c := range ccfgs { - //nolint:staticcheck //ignore EqualFold it broke ci for some reason (go version skew btw local and ci?) - if strings.ToLower(c.Network.ChainType.String()) == strings.ToLower(string(t)) { - return chainConfigFromClo(c), true + if c.Chain.Type == t { + return c, true } } return nil, false } -func registryChainConfig(ccfgs []*models.NodeChainConfig, t chaintype.ChainType, sel uint64) (*v1.ChainConfig, error) { +func registryChainConfig(ccfgs []*v1.ChainConfig, t v1.ChainType, sel uint64) (*v1.ChainConfig, error) { chainId, err := chainsel.ChainIdFromSelector(sel) if err != nil { return nil, fmt.Errorf("failed to get chain id from selector %d: %w", sel, err) } chainIdStr := strconv.FormatUint(chainId, 10) for _, c := range ccfgs { - //nolint:staticcheck //ignore EqualFold it broke ci for some reason (go version skew btw local and ci?) - if strings.ToLower(c.Network.ChainType.String()) == strings.ToLower(string(t)) && c.Network.ChainID == chainIdStr { - return chainConfigFromClo(c), nil + if c.Chain.Type == t && c.Chain.Id == chainIdStr { + return c, nil } } return nil, fmt.Errorf("no chain config for chain %d", chainId) @@ -350,7 +389,7 @@ func (d RegisteredDon) signers() []common.Address { return out } -func joinInfoAndNodes(donInfos map[string]kcr.CapabilitiesRegistryDONInfo, dons []DonCapabilities, registryChainSel uint64) ([]RegisteredDon, error) { +func joinInfoAndNodes(donInfos map[string]kcr.CapabilitiesRegistryDONInfo, dons []DonInfo, registryChainSel uint64) ([]RegisteredDon, error) { // all maps should have the same keys nodes, err := mapDonsToNodes(dons, true, registryChainSel) if err != nil { @@ -376,31 +415,6 @@ func joinInfoAndNodes(donInfos map[string]kcr.CapabilitiesRegistryDONInfo, dons return out, nil } -func chainConfigFromClo(chain *models.NodeChainConfig) *v1.ChainConfig { - return &v1.ChainConfig{ - Chain: &v1.Chain{ - Id: chain.Network.ChainID, - Type: v1.ChainType_CHAIN_TYPE_EVM, // TODO: support other chain types - }, - - AccountAddress: chain.AccountAddress, - AdminAddress: chain.AdminAddress, - Ocr2Config: &v1.OCR2Config{ - Enabled: chain.Ocr2Config.Enabled, - P2PKeyBundle: &v1.OCR2Config_P2PKeyBundle{ - PeerId: chain.Ocr2Config.P2pKeyBundle.PeerID, - PublicKey: chain.Ocr2Config.P2pKeyBundle.PublicKey, - }, - OcrKeyBundle: &v1.OCR2Config_OCRKeyBundle{ - BundleId: chain.Ocr2Config.OcrKeyBundle.BundleID, - OnchainSigningAddress: chain.Ocr2Config.OcrKeyBundle.OnchainSigningAddress, - OffchainPublicKey: chain.Ocr2Config.OcrKeyBundle.OffchainPublicKey, - ConfigPublicKey: chain.Ocr2Config.OcrKeyBundle.ConfigPublicKey, - }, - }, - } -} - var emptyAddr = "0x0000000000000000000000000000000000000000" // compute the admin address from the string. If the address is empty, replaces the 0s with fs diff --git a/deployment/keystone/types_test.go b/deployment/keystone/types_test.go index 69b2e39a8f1..925649bba0d 100644 --- a/deployment/keystone/types_test.go +++ b/deployment/keystone/types_test.go @@ -1,19 +1,11 @@ package keystone import ( - "encoding/json" - "os" - "strconv" "testing" "github.com/stretchr/testify/assert" - "github.com/test-go/testify/require" - - chainsel "github.com/smartcontractkit/chain-selectors" v1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node" - "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" - kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" ) @@ -140,271 +132,271 @@ func Test_newOcr2Node(t *testing.T) { } } -func Test_mapDonsToNodes(t *testing.T) { - var ( - pubKey = "03dacd15fc96c965c648e3623180de002b71a97cf6eeca9affb91f461dcd6ce1" - evmSig = "b35409a8d4f9a18da55c5b2bb08a3f5f68d44442" - aptosSig = "b35409a8d4f9a18da55c5b2bb08a3f5f68d44442b35409a8d4f9a18da55c5b2bb08a3f5f68d44442" - peerID = "p2p_12D3KooWMWUKdoAc2ruZf9f55p7NVFj7AFiPm67xjQ8BZBwkqyYv" - // todo: these should be defined in common - writerCap = 3 - ocr3Cap = 2 - registryChainSel = chainsel.ETHEREUM_TESTNET_SEPOLIA.Selector - registryChainID = strconv.FormatUint(chainsel.ETHEREUM_TESTNET_SEPOLIA.EvmChainID, 10) - ) - type args struct { - dons []DonCapabilities - excludeBootstraps bool - } - tests := []struct { - name string - args args - wantErr bool - }{ - { - name: "writer evm only", - args: args{ - dons: []DonCapabilities{ - { - Name: "ok writer", - Nops: []*models.NodeOperator{ - { - Nodes: []*models.Node{ - { - PublicKey: &pubKey, - ChainConfigs: []*models.NodeChainConfig{ - { - ID: "1", - Network: &models.Network{ - ChainType: models.ChainTypeEvm, - ChainID: registryChainID, - }, - Ocr2Config: &models.NodeOCR2Config{ - P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ - PeerID: peerID, - }, - OcrKeyBundle: &models.NodeOCR2ConfigOCRKeyBundle{ - ConfigPublicKey: pubKey, - OffchainPublicKey: pubKey, - OnchainSigningAddress: evmSig, - }, - }, - }, - }, - }, - }, - }, - }, - Capabilities: []kcr.CapabilitiesRegistryCapability{ - { - LabelledName: "writer", - Version: "1", - CapabilityType: uint8(writerCap), - }, - }, - }, - }, - }, - wantErr: false, - }, - { - name: "err if no evm chain", - args: args{ - dons: []DonCapabilities{ - { - Name: "bad chain", - Nops: []*models.NodeOperator{ - { - Nodes: []*models.Node{ - { - PublicKey: &pubKey, - ChainConfigs: []*models.NodeChainConfig{ - { - ID: "1", - Network: &models.Network{ - ChainType: models.ChainTypeSolana, - }, - Ocr2Config: &models.NodeOCR2Config{ - P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ - PeerID: peerID, - }, - OcrKeyBundle: &models.NodeOCR2ConfigOCRKeyBundle{ - ConfigPublicKey: pubKey, - OffchainPublicKey: pubKey, - OnchainSigningAddress: evmSig, - }, - }, - }, - }, - }, - }, - }, - }, - Capabilities: []kcr.CapabilitiesRegistryCapability{ - { - LabelledName: "writer", - Version: "1", - CapabilityType: uint8(writerCap), - }, - }, - }, - }, - }, - wantErr: true, - }, - { - name: "ocr3 cap evm only", - args: args{ - dons: []DonCapabilities{ - { - Name: "bad chain", - Nops: []*models.NodeOperator{ - { - Nodes: []*models.Node{ - { - PublicKey: &pubKey, - ChainConfigs: []*models.NodeChainConfig{ - { - ID: "1", - Network: &models.Network{ - ChainType: models.ChainTypeEvm, - ChainID: registryChainID, - }, - Ocr2Config: &models.NodeOCR2Config{ - P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ - PeerID: peerID, - }, - OcrKeyBundle: &models.NodeOCR2ConfigOCRKeyBundle{ - ConfigPublicKey: pubKey, - OffchainPublicKey: pubKey, - OnchainSigningAddress: evmSig, - }, - }, - }, - }, - }, - }, - }, - }, - Capabilities: []kcr.CapabilitiesRegistryCapability{ - { - LabelledName: "ocr3", - Version: "1", - CapabilityType: uint8(ocr3Cap), - }, - }, - }, - }, - }, - wantErr: false, - }, - { - name: "ocr3 cap evm & aptos", - args: args{ - dons: []DonCapabilities{ - { - Name: "ok chain", - Nops: []*models.NodeOperator{ - { - Nodes: []*models.Node{ - { - PublicKey: &pubKey, - ChainConfigs: []*models.NodeChainConfig{ - { - ID: "1", - Network: &models.Network{ - ChainType: models.ChainTypeEvm, - ChainID: registryChainID, - }, - Ocr2Config: &models.NodeOCR2Config{ - P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ - PeerID: peerID, - }, - OcrKeyBundle: &models.NodeOCR2ConfigOCRKeyBundle{ - ConfigPublicKey: pubKey, - OffchainPublicKey: pubKey, - OnchainSigningAddress: evmSig, - }, - }, - }, - { - ID: "2", - Network: &models.Network{ - ChainType: models.ChainTypeAptos, - }, - Ocr2Config: &models.NodeOCR2Config{ - P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ - PeerID: peerID, - }, - OcrKeyBundle: &models.NodeOCR2ConfigOCRKeyBundle{ - ConfigPublicKey: pubKey, - OffchainPublicKey: pubKey, - OnchainSigningAddress: aptosSig, - }, - }, - }, - }, - }, - }, - }, - }, - Capabilities: []kcr.CapabilitiesRegistryCapability{ - { - LabelledName: "ocr3", - Version: "1", - CapabilityType: uint8(ocr3Cap), - }, - }, - }, - }, - }, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - _, err := mapDonsToNodes(tt.args.dons, tt.args.excludeBootstraps, registryChainSel) - if (err != nil) != tt.wantErr { - t.Errorf("mapDonsToNodes() error = %v, wantErr %v", err, tt.wantErr) - return - } - }) - } - // make sure the clo test data is correct - wfNops := loadTestNops(t, "testdata/workflow_nodes.json") - cwNops := loadTestNops(t, "testdata/chain_writer_nodes.json") - assetNops := loadTestNops(t, "testdata/asset_nodes.json") - require.Len(t, wfNops, 10) - require.Len(t, cwNops, 10) - require.Len(t, assetNops, 16) +// func Test_mapDonsToNodes(t *testing.T) { +// var ( +// pubKey = "03dacd15fc96c965c648e3623180de002b71a97cf6eeca9affb91f461dcd6ce1" +// evmSig = "b35409a8d4f9a18da55c5b2bb08a3f5f68d44442" +// aptosSig = "b35409a8d4f9a18da55c5b2bb08a3f5f68d44442b35409a8d4f9a18da55c5b2bb08a3f5f68d44442" +// peerID = "p2p_12D3KooWMWUKdoAc2ruZf9f55p7NVFj7AFiPm67xjQ8BZBwkqyYv" +// // todo: these should be defined in common +// writerCap = 3 +// ocr3Cap = 2 +// registryChainSel = chainsel.ETHEREUM_TESTNET_SEPOLIA.Selector +// registryChainID = strconv.FormatUint(chainsel.ETHEREUM_TESTNET_SEPOLIA.EvmChainID, 10) +// ) +// type args struct { +// dons []DonCapabilities +// excludeBootstraps bool +// } +// tests := []struct { +// name string +// args args +// wantErr bool +// }{ +// { +// name: "writer evm only", +// args: args{ +// dons: []DonCapabilities{ +// { +// Name: "ok writer", +// Nops: []*models.NodeOperator{ +// { +// Nodes: []*models.Node{ +// { +// PublicKey: &pubKey, +// ChainConfigs: []*models.NodeChainConfig{ +// { +// ID: "1", +// Network: &models.Network{ +// ChainType: models.ChainTypeEvm, +// ChainID: registryChainID, +// }, +// Ocr2Config: &models.NodeOCR2Config{ +// P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ +// PeerID: peerID, +// }, +// OcrKeyBundle: &models.NodeOCR2ConfigOCRKeyBundle{ +// ConfigPublicKey: pubKey, +// OffchainPublicKey: pubKey, +// OnchainSigningAddress: evmSig, +// }, +// }, +// }, +// }, +// }, +// }, +// }, +// }, +// Capabilities: []kcr.CapabilitiesRegistryCapability{ +// { +// LabelledName: "writer", +// Version: "1", +// CapabilityType: uint8(writerCap), +// }, +// }, +// }, +// }, +// }, +// wantErr: false, +// }, +// { +// name: "err if no evm chain", +// args: args{ +// dons: []DonCapabilities{ +// { +// Name: "bad chain", +// Nops: []*models.NodeOperator{ +// { +// Nodes: []*models.Node{ +// { +// PublicKey: &pubKey, +// ChainConfigs: []*models.NodeChainConfig{ +// { +// ID: "1", +// Network: &models.Network{ +// ChainType: models.ChainTypeSolana, +// }, +// Ocr2Config: &models.NodeOCR2Config{ +// P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ +// PeerID: peerID, +// }, +// OcrKeyBundle: &models.NodeOCR2ConfigOCRKeyBundle{ +// ConfigPublicKey: pubKey, +// OffchainPublicKey: pubKey, +// OnchainSigningAddress: evmSig, +// }, +// }, +// }, +// }, +// }, +// }, +// }, +// }, +// Capabilities: []kcr.CapabilitiesRegistryCapability{ +// { +// LabelledName: "writer", +// Version: "1", +// CapabilityType: uint8(writerCap), +// }, +// }, +// }, +// }, +// }, +// wantErr: true, +// }, +// { +// name: "ocr3 cap evm only", +// args: args{ +// dons: []DonCapabilities{ +// { +// Name: "bad chain", +// Nops: []*models.NodeOperator{ +// { +// Nodes: []*models.Node{ +// { +// PublicKey: &pubKey, +// ChainConfigs: []*models.NodeChainConfig{ +// { +// ID: "1", +// Network: &models.Network{ +// ChainType: models.ChainTypeEvm, +// ChainID: registryChainID, +// }, +// Ocr2Config: &models.NodeOCR2Config{ +// P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ +// PeerID: peerID, +// }, +// OcrKeyBundle: &models.NodeOCR2ConfigOCRKeyBundle{ +// ConfigPublicKey: pubKey, +// OffchainPublicKey: pubKey, +// OnchainSigningAddress: evmSig, +// }, +// }, +// }, +// }, +// }, +// }, +// }, +// }, +// Capabilities: []kcr.CapabilitiesRegistryCapability{ +// { +// LabelledName: "ocr3", +// Version: "1", +// CapabilityType: uint8(ocr3Cap), +// }, +// }, +// }, +// }, +// }, +// wantErr: false, +// }, +// { +// name: "ocr3 cap evm & aptos", +// args: args{ +// dons: []DonCapabilities{ +// { +// Name: "ok chain", +// Nops: []*models.NodeOperator{ +// { +// Nodes: []*models.Node{ +// { +// PublicKey: &pubKey, +// ChainConfigs: []*models.NodeChainConfig{ +// { +// ID: "1", +// Network: &models.Network{ +// ChainType: models.ChainTypeEvm, +// ChainID: registryChainID, +// }, +// Ocr2Config: &models.NodeOCR2Config{ +// P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ +// PeerID: peerID, +// }, +// OcrKeyBundle: &models.NodeOCR2ConfigOCRKeyBundle{ +// ConfigPublicKey: pubKey, +// OffchainPublicKey: pubKey, +// OnchainSigningAddress: evmSig, +// }, +// }, +// }, +// { +// ID: "2", +// Network: &models.Network{ +// ChainType: models.ChainTypeAptos, +// }, +// Ocr2Config: &models.NodeOCR2Config{ +// P2pKeyBundle: &models.NodeOCR2ConfigP2PKeyBundle{ +// PeerID: peerID, +// }, +// OcrKeyBundle: &models.NodeOCR2ConfigOCRKeyBundle{ +// ConfigPublicKey: pubKey, +// OffchainPublicKey: pubKey, +// OnchainSigningAddress: aptosSig, +// }, +// }, +// }, +// }, +// }, +// }, +// }, +// }, +// Capabilities: []kcr.CapabilitiesRegistryCapability{ +// { +// LabelledName: "ocr3", +// Version: "1", +// CapabilityType: uint8(ocr3Cap), +// }, +// }, +// }, +// }, +// }, +// wantErr: false, +// }, +// } +// for _, tt := range tests { +// t.Run(tt.name, func(t *testing.T) { +// _, err := mapDonsToNodes(tt.args.dons, tt.args.excludeBootstraps, registryChainSel) +// if (err != nil) != tt.wantErr { +// t.Errorf("mapDonsToNodes() error = %v, wantErr %v", err, tt.wantErr) +// return +// } +// }) +// } +// // make sure the clo test data is correct +// wfNops := loadTestNops(t, "testdata/workflow_nodes.json") +// cwNops := loadTestNops(t, "testdata/chain_writer_nodes.json") +// assetNops := loadTestNops(t, "testdata/asset_nodes.json") +// require.Len(t, wfNops, 10) +// require.Len(t, cwNops, 10) +// require.Len(t, assetNops, 16) - wfDon := DonCapabilities{ - Name: WFDonName, - Nops: wfNops, - Capabilities: []kcr.CapabilitiesRegistryCapability{OCR3Cap}, - } - cwDon := DonCapabilities{ - Name: TargetDonName, - Nops: cwNops, - Capabilities: []kcr.CapabilitiesRegistryCapability{WriteChainCap}, - } - assetDon := DonCapabilities{ - Name: StreamDonName, - Nops: assetNops, - Capabilities: []kcr.CapabilitiesRegistryCapability{StreamTriggerCap}, - } - _, err := mapDonsToNodes([]DonCapabilities{wfDon}, false, registryChainSel) - require.NoError(t, err, "failed to map wf don") - _, err = mapDonsToNodes([]DonCapabilities{cwDon}, false, registryChainSel) - require.NoError(t, err, "failed to map cw don") - _, err = mapDonsToNodes([]DonCapabilities{assetDon}, false, registryChainSel) - require.NoError(t, err, "failed to map asset don") -} +// wfDon := DonCapabilities{ +// Name: WFDonName, +// Nops: wfNops, +// Capabilities: []kcr.CapabilitiesRegistryCapability{OCR3Cap}, +// } +// cwDon := DonCapabilities{ +// Name: TargetDonName, +// Nops: cwNops, +// Capabilities: []kcr.CapabilitiesRegistryCapability{WriteChainCap}, +// } +// assetDon := DonCapabilities{ +// Name: StreamDonName, +// Nops: assetNops, +// Capabilities: []kcr.CapabilitiesRegistryCapability{StreamTriggerCap}, +// } +// _, err := mapDonsToNodes([]DonCapabilities{wfDon}, false, registryChainSel) +// require.NoError(t, err, "failed to map wf don") +// _, err = mapDonsToNodes([]DonCapabilities{cwDon}, false, registryChainSel) +// require.NoError(t, err, "failed to map cw don") +// _, err = mapDonsToNodes([]DonCapabilities{assetDon}, false, registryChainSel) +// require.NoError(t, err, "failed to map asset don") +// } -func loadTestNops(t *testing.T, pth string) []*models.NodeOperator { - f, err := os.ReadFile(pth) - require.NoError(t, err) - var nops []*models.NodeOperator - require.NoError(t, json.Unmarshal(f, &nops)) - return nops -} +// func loadTestNops(t *testing.T, pth string) []*models.NodeOperator { +// f, err := os.ReadFile(pth) +// require.NoError(t, err) +// var nops []*models.NodeOperator +// require.NoError(t, json.Unmarshal(f, &nops)) +// return nops +// } diff --git a/shell.nix b/shell.nix index e3b187dcd96..8d5b4351b25 100644 --- a/shell.nix +++ b/shell.nix @@ -1,7 +1,7 @@ {pkgs, isCrib}: with pkgs; let go = go_1_21; - postgresql = postgresql_14; + postgresql = postgresql_15; nodejs = nodejs-18_x; nodePackages = pkgs.nodePackages.override {inherit nodejs;}; pnpm = pnpm_9; From f822149802b887091f653876e977d2893128a586 Mon Sep 17 00:00:00 2001 From: jlaveracll Date: Wed, 13 Nov 2024 17:16:15 -0300 Subject: [PATCH 14/14] [NONEVM-904] Bump chain-selectors to v1.0.29 (#15209) * bump chain-selectors to v1.0.28 * bump everywhere else * bump chain-selector to v1.0.29 --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- deployment/go.mod | 2 +- deployment/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 ++-- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 2004dd7620d..caf3d5e68e6 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -293,7 +293,7 @@ require ( github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil/v3 v3.24.3 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240926212305-a6deabdfce86 // indirect - github.com/smartcontractkit/chain-selectors v1.0.27 // indirect + github.com/smartcontractkit/chain-selectors v1.0.29 // indirect github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b // indirect github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 5dd235b828f..362d28f28c3 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1088,8 +1088,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240926212305-a6deabdfce86 h1:qQH6fZZe31nBAG6INHph3z5ysDTPptyu0TR9uoJ1+ok= github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240926212305-a6deabdfce86/go.mod h1:WtWOoVQQEHxRHL2hNmuRrvDfYfQG/CioFNoa9Rr2mBE= -github.com/smartcontractkit/chain-selectors v1.0.27 h1:VE/ftX9Aae4gnw67yR1raKi+30iWKL/sWq8uyiLHM8k= -github.com/smartcontractkit/chain-selectors v1.0.27/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= +github.com/smartcontractkit/chain-selectors v1.0.29 h1:aZ9+OoUSMn4nqnissHtDvDoKR7JONfDqTHX3MHYIUIE= +github.com/smartcontractkit/chain-selectors v1.0.29/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b h1:4kmZtaQ4fXwduHnw9xk5VmiIOW4nHg/Mx6iidlZJt5o= diff --git a/deployment/go.mod b/deployment/go.mod index 608f3493d92..19720794189 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -21,7 +21,7 @@ require ( github.com/rs/zerolog v1.33.0 github.com/sethvargo/go-retry v0.2.4 github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240926212305-a6deabdfce86 - github.com/smartcontractkit/chain-selectors v1.0.27 + github.com/smartcontractkit/chain-selectors v1.0.29 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371 github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 diff --git a/deployment/go.sum b/deployment/go.sum index 20fcdbd861a..ce9bf9e0b7f 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1378,8 +1378,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240926212305-a6deabdfce86 h1:qQH6fZZe31nBAG6INHph3z5ysDTPptyu0TR9uoJ1+ok= github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240926212305-a6deabdfce86/go.mod h1:WtWOoVQQEHxRHL2hNmuRrvDfYfQG/CioFNoa9Rr2mBE= -github.com/smartcontractkit/chain-selectors v1.0.27 h1:VE/ftX9Aae4gnw67yR1raKi+30iWKL/sWq8uyiLHM8k= -github.com/smartcontractkit/chain-selectors v1.0.27/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= +github.com/smartcontractkit/chain-selectors v1.0.29 h1:aZ9+OoUSMn4nqnissHtDvDoKR7JONfDqTHX3MHYIUIE= +github.com/smartcontractkit/chain-selectors v1.0.29/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b h1:4kmZtaQ4fXwduHnw9xk5VmiIOW4nHg/Mx6iidlZJt5o= diff --git a/go.mod b/go.mod index 74e16a69202..2b6f03333c0 100644 --- a/go.mod +++ b/go.mod @@ -74,7 +74,7 @@ require ( github.com/scylladb/go-reflectx v1.0.1 github.com/shirou/gopsutil/v3 v3.24.3 github.com/shopspring/decimal v1.4.0 - github.com/smartcontractkit/chain-selectors v1.0.27 + github.com/smartcontractkit/chain-selectors v1.0.29 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371 diff --git a/go.sum b/go.sum index ddf3d1a8c39..13217384ff6 100644 --- a/go.sum +++ b/go.sum @@ -1072,8 +1072,8 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smartcontractkit/chain-selectors v1.0.27 h1:VE/ftX9Aae4gnw67yR1raKi+30iWKL/sWq8uyiLHM8k= -github.com/smartcontractkit/chain-selectors v1.0.27/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= +github.com/smartcontractkit/chain-selectors v1.0.29 h1:aZ9+OoUSMn4nqnissHtDvDoKR7JONfDqTHX3MHYIUIE= +github.com/smartcontractkit/chain-selectors v1.0.29/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b h1:4kmZtaQ4fXwduHnw9xk5VmiIOW4nHg/Mx6iidlZJt5o= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 875ea7dcfe3..aba17e10397 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -34,7 +34,7 @@ require ( github.com/segmentio/ksuid v1.0.4 github.com/shopspring/decimal v1.4.0 github.com/slack-go/slack v0.15.0 - github.com/smartcontractkit/chain-selectors v1.0.27 + github.com/smartcontractkit/chain-selectors v1.0.29 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b github.com/smartcontractkit/chainlink-common v0.3.1-0.20241113142256-8a7a997a0371 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 9db5e175661..5e6793bbb0f 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1399,8 +1399,8 @@ github.com/slack-go/slack v0.15.0 h1:LE2lj2y9vqqiOf+qIIy0GvEoxgF1N5yLGZffmEZykt0 github.com/slack-go/slack v0.15.0/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240926212305-a6deabdfce86 h1:qQH6fZZe31nBAG6INHph3z5ysDTPptyu0TR9uoJ1+ok= github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240926212305-a6deabdfce86/go.mod h1:WtWOoVQQEHxRHL2hNmuRrvDfYfQG/CioFNoa9Rr2mBE= -github.com/smartcontractkit/chain-selectors v1.0.27 h1:VE/ftX9Aae4gnw67yR1raKi+30iWKL/sWq8uyiLHM8k= -github.com/smartcontractkit/chain-selectors v1.0.27/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= +github.com/smartcontractkit/chain-selectors v1.0.29 h1:aZ9+OoUSMn4nqnissHtDvDoKR7JONfDqTHX3MHYIUIE= +github.com/smartcontractkit/chain-selectors v1.0.29/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b h1:4kmZtaQ4fXwduHnw9xk5VmiIOW4nHg/Mx6iidlZJt5o= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 54fed1df1b2..c89baf21bd9 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -420,7 +420,7 @@ require ( github.com/shoenig/test v0.6.6 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/smartcontractkit/chain-selectors v1.0.27 // indirect + github.com/smartcontractkit/chain-selectors v1.0.29 // indirect github.com/smartcontractkit/chainlink-automation v0.8.1 // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index b287474056e..f2c309ea33a 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1388,8 +1388,8 @@ 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.15.0 h1:LE2lj2y9vqqiOf+qIIy0GvEoxgF1N5yLGZffmEZykt0= github.com/slack-go/slack v0.15.0/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= -github.com/smartcontractkit/chain-selectors v1.0.27 h1:VE/ftX9Aae4gnw67yR1raKi+30iWKL/sWq8uyiLHM8k= -github.com/smartcontractkit/chain-selectors v1.0.27/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= +github.com/smartcontractkit/chain-selectors v1.0.29 h1:aZ9+OoUSMn4nqnissHtDvDoKR7JONfDqTHX3MHYIUIE= +github.com/smartcontractkit/chain-selectors v1.0.29/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b h1:4kmZtaQ4fXwduHnw9xk5VmiIOW4nHg/Mx6iidlZJt5o=