From baa225e7614f504a70cb51a8b0d0a98402971268 Mon Sep 17 00:00:00 2001 From: Josh Weintraub <26035072+jhweintraub@users.noreply.github.com> Date: Tue, 17 Dec 2024 08:00:54 -0500 Subject: [PATCH 01/27] CCIP-4476 remove legacy curse check in rmnRemote (#15523) * add legacy curse check to offramps * fill in coverage test gap * remove legacy curse subject from RMNRemote * snapshot, wrapper, and changeset fix * [Bot] Update changeset file with jira issues * snapshot fix * Update test naming and comments --------- Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com> --- contracts/.changeset/eighty-cycles-film.md | 10 ++++++++++ contracts/gas-snapshots/ccip.gas-snapshot | 2 +- contracts/src/v0.8/ccip/rmn/RMNRemote.sol | 9 ++------- ...cyCurses.t.sol => RMNRemote.globalCurses.t.sol} | 14 +++----------- .../ccip/generated/rmn_remote/rmn_remote.go | 2 +- ...ted-wrapper-dependency-versions-do-not-edit.txt | 2 +- 6 files changed, 18 insertions(+), 21 deletions(-) create mode 100644 contracts/.changeset/eighty-cycles-film.md rename contracts/src/v0.8/ccip/test/rmn/RMNRemote/{RMNRemote.globalAndLegacyCurses.t.sol => RMNRemote.globalCurses.t.sol} (51%) diff --git a/contracts/.changeset/eighty-cycles-film.md b/contracts/.changeset/eighty-cycles-film.md new file mode 100644 index 00000000000..6cd56afa80a --- /dev/null +++ b/contracts/.changeset/eighty-cycles-film.md @@ -0,0 +1,10 @@ +--- +'@chainlink/contracts': patch +--- + +remove legacy curse check from RMNRemote isCursed() method #bugfix + + +PR issue: CCIP-4476 + +Solidity Review issue: CCIP-3966 \ No newline at end of file diff --git a/contracts/gas-snapshots/ccip.gas-snapshot b/contracts/gas-snapshots/ccip.gas-snapshot index d655e886262..147783b52cb 100644 --- a/contracts/gas-snapshots/ccip.gas-snapshot +++ b/contracts/gas-snapshots/ccip.gas-snapshot @@ -572,7 +572,7 @@ RMNRemote_constructor:test_constructor() (gas: 8398) RMNRemote_curse:test_curse_AlreadyCursed_duplicateSubject_reverts() (gas: 154501) RMNRemote_curse:test_curse_calledByNonOwner_reverts() (gas: 18734) RMNRemote_curse:test_curse_success() (gas: 149475) -RMNRemote_global_and_legacy_curses:test_global_and_legacy_curses_success() (gas: 133441) +RMNRemote_global_curses:test_isCursed_globalCurseSubject() (gas: 71715) RMNRemote_isBlessed:test_isBlessed() (gas: 17588) RMNRemote_setConfig:test_setConfig_ZeroValueNotAllowed_revert() (gas: 37971) RMNRemote_setConfig:test_setConfig_addSigner_removeSigner_success() (gas: 993448) diff --git a/contracts/src/v0.8/ccip/rmn/RMNRemote.sol b/contracts/src/v0.8/ccip/rmn/RMNRemote.sol index 4e7ce766443..83445193ad1 100644 --- a/contracts/src/v0.8/ccip/rmn/RMNRemote.sol +++ b/contracts/src/v0.8/ccip/rmn/RMNRemote.sol @@ -9,11 +9,6 @@ import {Ownable2StepMsgSender} from "../../shared/access/Ownable2StepMsgSender.s import {EnumerableSet} from "../../shared/enumerable/EnumerableSetWithBytes16.sol"; import {Internal} from "../libraries/Internal.sol"; -/// @dev An active curse on this subject will cause isCursed() to return true. Use this subject if there is an issue -/// with a remote chain, for which there exists a legacy lane contract deployed on the same chain as this RMN contract -/// is deployed, relying on isCursed(). -bytes16 constant LEGACY_CURSE_SUBJECT = 0x01000000000000000000000000000000; - /// @dev An active curse on this subject will cause isCursed() and isCursed(bytes16) to return true. Use this subject /// for issues affecting all of CCIP chains, or pertaining to the chain that this contract is deployed on, instead of /// using the local chain selector as a subject. @@ -256,11 +251,11 @@ contract RMNRemote is Ownable2StepMsgSender, ITypeAndVersion, IRMNRemote, IRMN { /// @inheritdoc IRMNRemote function isCursed() external view override(IRMN, IRMNRemote) returns (bool) { // There are zero curses under normal circumstances, which means it's cheaper to check for the absence of curses. - // than to check the subject list twice, as we have to check for both the legacy and global curse subjects. + // than to check the subject list for the global curse subject. if (s_cursedSubjects.length() == 0) { return false; } - return s_cursedSubjects.contains(LEGACY_CURSE_SUBJECT) || s_cursedSubjects.contains(GLOBAL_CURSE_SUBJECT); + return s_cursedSubjects.contains(GLOBAL_CURSE_SUBJECT); } /// @inheritdoc IRMNRemote diff --git a/contracts/src/v0.8/ccip/test/rmn/RMNRemote/RMNRemote.globalAndLegacyCurses.t.sol b/contracts/src/v0.8/ccip/test/rmn/RMNRemote/RMNRemote.globalCurses.t.sol similarity index 51% rename from contracts/src/v0.8/ccip/test/rmn/RMNRemote/RMNRemote.globalAndLegacyCurses.t.sol rename to contracts/src/v0.8/ccip/test/rmn/RMNRemote/RMNRemote.globalCurses.t.sol index da6677678fe..6524e2545e5 100644 --- a/contracts/src/v0.8/ccip/test/rmn/RMNRemote/RMNRemote.globalAndLegacyCurses.t.sol +++ b/contracts/src/v0.8/ccip/test/rmn/RMNRemote/RMNRemote.globalCurses.t.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.24; -import {GLOBAL_CURSE_SUBJECT, LEGACY_CURSE_SUBJECT} from "../../../rmn/RMNRemote.sol"; +import {GLOBAL_CURSE_SUBJECT} from "../../../rmn/RMNRemote.sol"; import {RMNRemoteSetup} from "./RMNRemoteSetup.t.sol"; -contract RMNRemote_global_and_legacy_curses is RMNRemoteSetup { - function test_global_and_legacy_curses_success() public { +contract RMNRemote_global_curses is RMNRemoteSetup { + function test_isCursed_globalCurseSubject() public { bytes16 randSubject = bytes16(keccak256("random subject")); assertFalse(s_rmnRemote.isCursed()); assertFalse(s_rmnRemote.isCursed(randSubject)); @@ -17,13 +17,5 @@ contract RMNRemote_global_and_legacy_curses is RMNRemoteSetup { s_rmnRemote.uncurse(GLOBAL_CURSE_SUBJECT); assertFalse(s_rmnRemote.isCursed()); assertFalse(s_rmnRemote.isCursed(randSubject)); - - s_rmnRemote.curse(LEGACY_CURSE_SUBJECT); - assertTrue(s_rmnRemote.isCursed()); - assertFalse(s_rmnRemote.isCursed(randSubject)); // legacy curse doesn't affect specific subjects - - s_rmnRemote.uncurse(LEGACY_CURSE_SUBJECT); - assertFalse(s_rmnRemote.isCursed()); - assertFalse(s_rmnRemote.isCursed(randSubject)); } } diff --git a/core/gethwrappers/ccip/generated/rmn_remote/rmn_remote.go b/core/gethwrappers/ccip/generated/rmn_remote/rmn_remote.go index 2c7c367ab1f..31b657c6ce0 100644 --- a/core/gethwrappers/ccip/generated/rmn_remote/rmn_remote.go +++ b/core/gethwrappers/ccip/generated/rmn_remote/rmn_remote.go @@ -61,7 +61,7 @@ type RMNRemoteSigner struct { var RMNRemoteMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"localChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"contractIRMN\",\"name\":\"legacyRMN\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"}],\"name\":\"AlreadyCursed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"CannotTransferToSelf\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ConfigNotSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DuplicateOnchainPublicKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSignerOrder\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"IsBlessedNotAvailable\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeProposedOwner\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"}],\"name\":\"NotCursed\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotEnoughSigners\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OutOfOrderSignatures\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OwnerCannotBeZero\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ThresholdNotMet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnexpectedSigner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroValueNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint32\",\"name\":\"version\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"rmnHomeContractConfigDigest\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"onchainPublicKey\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"nodeIndex\",\"type\":\"uint64\"}],\"internalType\":\"structRMNRemote.Signer[]\",\"name\":\"signers\",\"type\":\"tuple[]\"},{\"internalType\":\"uint64\",\"name\":\"f\",\"type\":\"uint64\"}],\"indexed\":false,\"internalType\":\"structRMNRemote.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes16[]\",\"name\":\"subjects\",\"type\":\"bytes16[]\"}],\"name\":\"Cursed\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes16[]\",\"name\":\"subjects\",\"type\":\"bytes16[]\"}],\"name\":\"Uncursed\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"}],\"name\":\"curse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes16[]\",\"name\":\"subjects\",\"type\":\"bytes16[]\"}],\"name\":\"curse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCursedSubjects\",\"outputs\":[{\"internalType\":\"bytes16[]\",\"name\":\"subjects\",\"type\":\"bytes16[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLocalChainSelector\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"localChainSelector\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getReportDigestHeader\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"digestHeader\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getVersionedConfig\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"version\",\"type\":\"uint32\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"rmnHomeContractConfigDigest\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"onchainPublicKey\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"nodeIndex\",\"type\":\"uint64\"}],\"internalType\":\"structRMNRemote.Signer[]\",\"name\":\"signers\",\"type\":\"tuple[]\"},{\"internalType\":\"uint64\",\"name\":\"f\",\"type\":\"uint64\"}],\"internalType\":\"structRMNRemote.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"commitStore\",\"type\":\"address\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structIRMN.TaggedRoot\",\"name\":\"taggedRoot\",\"type\":\"tuple\"}],\"name\":\"isBlessed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"}],\"name\":\"isCursed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"isCursed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"rmnHomeContractConfigDigest\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"onchainPublicKey\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"nodeIndex\",\"type\":\"uint64\"}],\"internalType\":\"structRMNRemote.Signer[]\",\"name\":\"signers\",\"type\":\"tuple[]\"},{\"internalType\":\"uint64\",\"name\":\"f\",\"type\":\"uint64\"}],\"internalType\":\"structRMNRemote.Config\",\"name\":\"newConfig\",\"type\":\"tuple\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes16\",\"name\":\"subject\",\"type\":\"bytes16\"}],\"name\":\"uncurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes16[]\",\"name\":\"subjects\",\"type\":\"bytes16[]\"}],\"name\":\"uncurse\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"offrampAddress\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"onRampAddress\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"minSeqNr\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"maxSeqNr\",\"type\":\"uint64\"},{\"internalType\":\"bytes32\",\"name\":\"merkleRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structInternal.MerkleRoot[]\",\"name\":\"merkleRoots\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"}],\"internalType\":\"structIRMNRemote.Signature[]\",\"name\":\"signatures\",\"type\":\"tuple[]\"}],\"name\":\"verify\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60c06040523480156200001157600080fd5b506040516200230438038062002304833981016040819052620000349162000150565b336000816200005657604051639b15e16f60e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b038481169190911790915581161562000089576200008981620000d6565b5050816001600160401b0316600003620000b65760405163273e150360e21b815260040160405180910390fd5b6001600160401b039091166080526001600160a01b031660a052620001a5565b336001600160a01b038216036200010057604051636d6c4ee560e11b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b03838116918217835560015460405192939116917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080604083850312156200016457600080fd5b82516001600160401b03811681146200017c57600080fd5b60208401519092506001600160a01b03811681146200019a57600080fd5b809150509250929050565b60805160a05161212b620001d9600039600081816108c5015261096d0152600081816102a80152610b7c015261212b6000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c80636d2d3993116100b25780639a19b32911610081578063eaa83ddd11610066578063eaa83ddd1461029a578063f2fde38b146102d2578063f8bb876e146102e557600080fd5b80639a19b32914610272578063d881e0921461028557600080fd5b80636d2d39931461021c57806370a9089e1461022f57806379ba5097146102425780638da5cb5b1461024a57600080fd5b8063397796f7116100ee578063397796f7146101c05780634d616771146101c857806362eed415146101db5780636509a954146101ee57600080fd5b8063181f5a7714610120578063198f0f77146101725780631add205f146101875780632cbc26bb1461019d575b600080fd5b61015c6040518060400160405280601381526020017f524d4e52656d6f746520312e362e302d6465760000000000000000000000000081525081565b60405161016991906114d9565b60405180910390f35b6101856101803660046114ec565b6102f8565b005b61018f6106f2565b604051610169929190611527565b6101b06101ab366004611605565b6107ea565b6040519015158152602001610169565b6101b0610847565b6101b06101d6366004611620565b6108c1565b6101856101e9366004611605565b6109e3565b6040517f9651943783dbf81935a60e98f218a9d9b5b28823fb2228bbd91320d632facf538152602001610169565b61018561022a366004611605565b610a57565b61018561023d3660046116a6565b610ac7565b610185610e22565b60015460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610169565b610185610280366004611825565b610ef0565b61028d610ff6565b60405161016991906118c2565b60405167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610169565b6101856102e0366004611928565b611002565b6101856102f3366004611825565b611016565b610300611108565b8035610338576040517f9cf8540c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015b6103486020830183611945565b90508110156104185761035e6020830183611945565b8281811061036e5761036e6119ad565b905060400201602001602081019061038691906119fd565b67ffffffffffffffff1661039d6020840184611945565b6103a8600185611a49565b8181106103b7576103b76119ad565b90506040020160200160208101906103cf91906119fd565b67ffffffffffffffff1610610410576040517f4485151700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60010161033b565b5061042960608201604083016119fd565b610434906002611a5c565b61043f906001611a88565b67ffffffffffffffff166104566020830183611945565b90501015610490576040517f014c502000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003545b8015610522576008600060036104ab600185611a49565b815481106104bb576104bb6119ad565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905561051b81611aa9565b9050610494565b5060005b6105336020830183611945565b9050811015610668576008600061054d6020850185611945565b8481811061055d5761055d6119ad565b6105739260206040909202019081019150611928565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff16156105d4576040517f28cae27d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600860006105e76020860186611945565b858181106105f7576105f76119ad565b61060d9260206040909202019081019150611928565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055600101610526565b508060026106768282611b97565b5050600580546000919082906106919063ffffffff16611cd2565b91906101000a81548163ffffffff021916908363ffffffff160217905590508063ffffffff167f7f22bf988149dbe8de8fb879c6b97a4e56e68b2bd57421ce1a4e79d4ef6b496c836040516106e69190611cf5565b60405180910390a25050565b6040805160608082018352600080835260208301919091529181018290526005546040805160608101825260028054825260038054845160208281028201810190965281815263ffffffff9096169592948593818601939092909160009084015b828210156107c1576000848152602090819020604080518082019091529084015473ffffffffffffffffffffffffffffffffffffffff8116825274010000000000000000000000000000000000000000900467ffffffffffffffff1681830152825260019092019101610753565b505050908252506002919091015467ffffffffffffffff16602090910152919491935090915050565b60006107f6600661115b565b60000361080557506000919050565b610810600683611165565b80610841575061084160067f0100000000000000000000000000000100000000000000000000000000000000611165565b92915050565b6000610853600661115b565b6000036108605750600090565b61088b60067f0100000000000000000000000000000000000000000000000000000000000000611165565b806108bc57506108bc60067f0100000000000000000000000000000100000000000000000000000000000000611165565b905090565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16610930576040517f0a7c4edd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f4d61677100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634d616771906109a2908590600401611dff565b602060405180830381865afa1580156109bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108419190611e38565b604080516001808252818301909252600091602080830190803683370190505090508181600081518110610a1957610a196119ad565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000090921660209283029190910190910152610a5381611016565b5050565b604080516001808252818301909252600091602080830190803683370190505090508181600081518110610a8d57610a8d6119ad565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000090921660209283029190910190910152610a5381610ef0565b60055463ffffffff16600003610b09576040517face124bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600454610b219067ffffffffffffffff166001611a88565b67ffffffffffffffff16811015610b64576040517f59fa4a9300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160c08101825246815267ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166020820152309181019190915273ffffffffffffffffffffffffffffffffffffffff8616606082015260025460808201526000907f9651943783dbf81935a60e98f218a9d9b5b28823fb2228bbd91320d632facf539060a08101610c008789611e5a565b9052604051610c13929190602001611fba565b60405160208183030381529060405280519060200120905060008060005b84811015610e1757600184601b888885818110610c5057610c506119ad565b90506040020160000135898986818110610c6c57610c6c6119ad565b9050604002016020013560405160008152602001604052604051610cac949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015610cce573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015192505073ffffffffffffffffffffffffffffffffffffffff8216610d46576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1610610dab576040517fbbe15e7f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526008602052604090205460ff16610e0a576040517faaaa914100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9091508190600101610c31565b505050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610e73576040517f02b543c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560008054909116815560405173ffffffffffffffffffffffffffffffffffffffff909216929183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610ef8611108565b60005b8151811015610fbb57610f31828281518110610f1957610f196119ad565b602002602001015160066111a390919063ffffffff16565b610fb357818181518110610f4757610f476119ad565b60200260200101516040517f73281fa1000000000000000000000000000000000000000000000000000000008152600401610faa91907fffffffffffffffffffffffffffffffff0000000000000000000000000000000091909116815260200190565b60405180910390fd5b600101610efb565b507f0676e709c9cc74fa0519fd78f7c33be0f1b2b0bae0507c724aef7229379c6ba181604051610feb91906118c2565b60405180910390a150565b60606108bc60066111d1565b61100a611108565b611013816111de565b50565b61101e611108565b60005b81518110156110d85761105782828151811061103f5761103f6119ad565b602002602001015160066112a290919063ffffffff16565b6110d05781818151811061106d5761106d6119ad565b60200260200101516040517f19d5c79b000000000000000000000000000000000000000000000000000000008152600401610faa91907fffffffffffffffffffffffffffffffff0000000000000000000000000000000091909116815260200190565b600101611021565b507f1716e663a90a76d3b6c7e5f680673d1b051454c19c627e184c8daf28f3104f7481604051610feb91906118c2565b60015473ffffffffffffffffffffffffffffffffffffffff163314611159576040517f2b5c74de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6000610841825490565b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116600090815260018301602052604081205415155b9392505050565b600061119c837fffffffffffffffffffffffffffffffff0000000000000000000000000000000084166112d0565b6060600061119c836113ca565b3373ffffffffffffffffffffffffffffffffffffffff82160361122d576040517fdad89dca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217835560015460405192939116917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061119c837fffffffffffffffffffffffffffffffff000000000000000000000000000000008416611426565b600081815260018301602052604081205480156113b95760006112f4600183611a49565b855490915060009061130890600190611a49565b905080821461136d576000866000018281548110611328576113286119ad565b906000526020600020015490508087600001848154811061134b5761134b6119ad565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061137e5761137e6120ef565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610841565b6000915050610841565b5092915050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561141a57602002820191906000526020600020905b815481526020019060010190808311611406575b50505050509050919050565b600081815260018301602052604081205461146d57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610841565b506000610841565b6000815180845260005b8181101561149b5760208185018101518683018201520161147f565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061119c6020830184611475565b6000602082840312156114fe57600080fd5b813567ffffffffffffffff81111561151557600080fd5b82016060818503121561119c57600080fd5b63ffffffff831681526040602080830182905283518383015283810151606080850152805160a085018190526000939291820190849060c08701905b808310156115ac578351805173ffffffffffffffffffffffffffffffffffffffff16835285015167ffffffffffffffff1685830152928401926001929092019190850190611563565b50604088015167ffffffffffffffff81166080890152945098975050505050505050565b80357fffffffffffffffffffffffffffffffff000000000000000000000000000000008116811461160057600080fd5b919050565b60006020828403121561161757600080fd5b61119c826115d0565b60006040828403121561163257600080fd5b50919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461101357600080fd5b60008083601f84011261166c57600080fd5b50813567ffffffffffffffff81111561168457600080fd5b6020830191508360208260061b850101111561169f57600080fd5b9250929050565b6000806000806000606086880312156116be57600080fd5b85356116c981611638565b9450602086013567ffffffffffffffff808211156116e657600080fd5b818801915088601f8301126116fa57600080fd5b81358181111561170957600080fd5b8960208260051b850101111561171e57600080fd5b60208301965080955050604088013591508082111561173c57600080fd5b506117498882890161165a565b969995985093965092949392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff811182821017156117ac576117ac61175a565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156117f9576117f961175a565b604052919050565b600067ffffffffffffffff82111561181b5761181b61175a565b5060051b60200190565b6000602080838503121561183857600080fd5b823567ffffffffffffffff81111561184f57600080fd5b8301601f8101851361186057600080fd5b803561187361186e82611801565b6117b2565b81815260059190911b8201830190838101908783111561189257600080fd5b928401925b828410156118b7576118a8846115d0565b82529284019290840190611897565b979650505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561191c5783517fffffffffffffffffffffffffffffffff0000000000000000000000000000000016835292840192918401916001016118de565b50909695505050505050565b60006020828403121561193a57600080fd5b813561119c81611638565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261197a57600080fd5b83018035915067ffffffffffffffff82111561199557600080fd5b6020019150600681901b360382131561169f57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b67ffffffffffffffff8116811461101357600080fd5b8035611600816119dc565b600060208284031215611a0f57600080fd5b813561119c816119dc565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111561084157610841611a1a565b67ffffffffffffffff818116838216028082169190828114611a8057611a80611a1a565b505092915050565b67ffffffffffffffff8181168382160190808211156113c3576113c3611a1a565b600081611ab857611ab8611a1a565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b60008135610841816119dc565b8135611af681611638565b73ffffffffffffffffffffffffffffffffffffffff811690508154817fffffffffffffffffffffffff000000000000000000000000000000000000000082161783556020840135611b46816119dc565b7bffffffffffffffff00000000000000000000000000000000000000008160a01b16837fffffffff000000000000000000000000000000000000000000000000000000008416171784555050505050565b81358155600180820160208401357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1853603018112611bd557600080fd5b8401803567ffffffffffffffff811115611bee57600080fd5b6020820191508060061b3603821315611c0657600080fd5b68010000000000000000811115611c1f57611c1f61175a565b825481845580821015611c54576000848152602081208381019083015b80821015611c505782825590870190611c3c565b5050505b50600092835260208320925b81811015611c8457611c728385611aeb565b92840192604092909201918401611c60565b5050505050610a53611c9860408401611ade565b6002830167ffffffffffffffff82167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008254161781555050565b600063ffffffff808316818103611ceb57611ceb611a1a565b6001019392505050565b6000602080835260808301843582850152818501357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1863603018112611d3a57600080fd5b8501828101903567ffffffffffffffff80821115611d5757600080fd5b8160061b3603831315611d6957600080fd5b6040606060408901528483865260a089019050849550600094505b83851015611dd4578535611d9781611638565b73ffffffffffffffffffffffffffffffffffffffff16815285870135611dbc816119dc565b83168188015294810194600194909401938101611d84565b611de060408b016119f2565b67ffffffffffffffff811660608b015296509998505050505050505050565b604081018235611e0e81611638565b73ffffffffffffffffffffffffffffffffffffffff81168352506020830135602083015292915050565b600060208284031215611e4a57600080fd5b8151801515811461119c57600080fd5b6000611e6861186e84611801565b80848252602080830192508560051b850136811115611e8657600080fd5b855b81811015611fae57803567ffffffffffffffff80821115611ea95760008081fd5b818901915060a08236031215611ebf5760008081fd5b611ec7611789565b8235611ed2816119dc565b81528286013582811115611ee65760008081fd5b8301601f3681830112611ef95760008081fd5b813584811115611f0b57611f0b61175a565b611f3a897fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe084840116016117b2565b94508085523689828501011115611f5357600091508182fd5b808984018a8701376000898287010152505050818682015260409150611f7a8284016119f2565b8282015260609150611f8d8284016119f2565b91810191909152608091820135918101919091528552938201938201611e88565b50919695505050505050565b60006040848352602060408185015261010084018551604086015281860151606067ffffffffffffffff808316606089015260408901519250608073ffffffffffffffffffffffffffffffffffffffff80851660808b015260608b0151945060a081861660a08c015260808c015160c08c015260a08c0151955060c060e08c015286915085518088526101209750878c019250878160051b8d01019750888701965060005b818110156120dc577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee08d8a030184528751868151168a528a810151848c8c01526120ab858c0182611475565b828e015189168c8f01528983015189168a8d0152918701519a87019a909a529850968901969289019260010161205f565b50969d9c50505050505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000818000a", + Bin: "0x60c06040523480156200001157600080fd5b50604051620022d3380380620022d3833981016040819052620000349162000150565b336000816200005657604051639b15e16f60e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b038481169190911790915581161562000089576200008981620000d6565b5050816001600160401b0316600003620000b65760405163273e150360e21b815260040160405180910390fd5b6001600160401b039091166080526001600160a01b031660a052620001a5565b336001600160a01b038216036200010057604051636d6c4ee560e11b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b03838116918217835560015460405192939116917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080604083850312156200016457600080fd5b82516001600160401b03811681146200017c57600080fd5b60208401519092506001600160a01b03811681146200019a57600080fd5b809150509250929050565b60805160a0516120fa620001d960003960008181610894015261093c0152600081816102a80152610b4b01526120fa6000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c80636d2d3993116100b25780639a19b32911610081578063eaa83ddd11610066578063eaa83ddd1461029a578063f2fde38b146102d2578063f8bb876e146102e557600080fd5b80639a19b32914610272578063d881e0921461028557600080fd5b80636d2d39931461021c57806370a9089e1461022f57806379ba5097146102425780638da5cb5b1461024a57600080fd5b8063397796f7116100ee578063397796f7146101c05780634d616771146101c857806362eed415146101db5780636509a954146101ee57600080fd5b8063181f5a7714610120578063198f0f77146101725780631add205f146101875780632cbc26bb1461019d575b600080fd5b61015c6040518060400160405280601381526020017f524d4e52656d6f746520312e362e302d6465760000000000000000000000000081525081565b60405161016991906114a8565b60405180910390f35b6101856101803660046114bb565b6102f8565b005b61018f6106f2565b6040516101699291906114f6565b6101b06101ab3660046115d4565b6107ea565b6040519015158152602001610169565b6101b0610847565b6101b06101d63660046115ef565b610890565b6101856101e93660046115d4565b6109b2565b6040517f9651943783dbf81935a60e98f218a9d9b5b28823fb2228bbd91320d632facf538152602001610169565b61018561022a3660046115d4565b610a26565b61018561023d366004611675565b610a96565b610185610df1565b60015460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610169565b6101856102803660046117f4565b610ebf565b61028d610fc5565b6040516101699190611891565b60405167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152602001610169565b6101856102e03660046118f7565b610fd1565b6101856102f33660046117f4565b610fe5565b6103006110d7565b8035610338576040517f9cf8540c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60015b6103486020830183611914565b90508110156104185761035e6020830183611914565b8281811061036e5761036e61197c565b905060400201602001602081019061038691906119cc565b67ffffffffffffffff1661039d6020840184611914565b6103a8600185611a18565b8181106103b7576103b761197c565b90506040020160200160208101906103cf91906119cc565b67ffffffffffffffff1610610410576040517f4485151700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60010161033b565b5061042960608201604083016119cc565b610434906002611a2b565b61043f906001611a57565b67ffffffffffffffff166104566020830183611914565b90501015610490576040517f014c502000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003545b8015610522576008600060036104ab600185611a18565b815481106104bb576104bb61197c565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff168352820192909252604001902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905561051b81611a78565b9050610494565b5060005b6105336020830183611914565b9050811015610668576008600061054d6020850185611914565b8481811061055d5761055d61197c565b61057392602060409092020190810191506118f7565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205460ff16156105d4576040517f28cae27d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600860006105e76020860186611914565b858181106105f7576105f761197c565b61060d92602060409092020190810191506118f7565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055600101610526565b508060026106768282611b66565b5050600580546000919082906106919063ffffffff16611ca1565b91906101000a81548163ffffffff021916908363ffffffff160217905590508063ffffffff167f7f22bf988149dbe8de8fb879c6b97a4e56e68b2bd57421ce1a4e79d4ef6b496c836040516106e69190611cc4565b60405180910390a25050565b6040805160608082018352600080835260208301919091529181018290526005546040805160608101825260028054825260038054845160208281028201810190965281815263ffffffff9096169592948593818601939092909160009084015b828210156107c1576000848152602090819020604080518082019091529084015473ffffffffffffffffffffffffffffffffffffffff8116825274010000000000000000000000000000000000000000900467ffffffffffffffff1681830152825260019092019101610753565b505050908252506002919091015467ffffffffffffffff16602090910152919491935090915050565b60006107f6600661112a565b60000361080557506000919050565b610810600683611134565b80610841575061084160067f0100000000000000000000000000000100000000000000000000000000000000611134565b92915050565b6000610853600661112a565b6000036108605750600090565b61088b60067f0100000000000000000000000000000100000000000000000000000000000000611134565b905090565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166108ff576040517f0a7c4edd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f4d61677100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634d61677190610971908590600401611dce565b602060405180830381865afa15801561098e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108419190611e07565b6040805160018082528183019092526000916020808301908036833701905050905081816000815181106109e8576109e861197c565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000090921660209283029190910190910152610a2281610fe5565b5050565b604080516001808252818301909252600091602080830190803683370190505090508181600081518110610a5c57610a5c61197c565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000090921660209283029190910190910152610a2281610ebf565b60055463ffffffff16600003610ad8576040517face124bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600454610af09067ffffffffffffffff166001611a57565b67ffffffffffffffff16811015610b33576040517f59fa4a9300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040805160c08101825246815267ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166020820152309181019190915273ffffffffffffffffffffffffffffffffffffffff8616606082015260025460808201526000907f9651943783dbf81935a60e98f218a9d9b5b28823fb2228bbd91320d632facf539060a08101610bcf8789611e29565b9052604051610be2929190602001611f89565b60405160208183030381529060405280519060200120905060008060005b84811015610de657600184601b888885818110610c1f57610c1f61197c565b90506040020160000135898986818110610c3b57610c3b61197c565b9050604002016020013560405160008152602001604052604051610c7b949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015610c9d573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015192505073ffffffffffffffffffffffffffffffffffffffff8216610d15576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1610610d7a576040517fbbe15e7f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081526008602052604090205460ff16610dd9576040517faaaa914100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9091508190600101610c00565b505050505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610e42576040517f02b543c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560008054909116815560405173ffffffffffffffffffffffffffffffffffffffff909216929183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610ec76110d7565b60005b8151811015610f8a57610f00828281518110610ee857610ee861197c565b6020026020010151600661117290919063ffffffff16565b610f8257818181518110610f1657610f1661197c565b60200260200101516040517f73281fa1000000000000000000000000000000000000000000000000000000008152600401610f7991907fffffffffffffffffffffffffffffffff0000000000000000000000000000000091909116815260200190565b60405180910390fd5b600101610eca565b507f0676e709c9cc74fa0519fd78f7c33be0f1b2b0bae0507c724aef7229379c6ba181604051610fba9190611891565b60405180910390a150565b606061088b60066111a0565b610fd96110d7565b610fe2816111ad565b50565b610fed6110d7565b60005b81518110156110a75761102682828151811061100e5761100e61197c565b6020026020010151600661127190919063ffffffff16565b61109f5781818151811061103c5761103c61197c565b60200260200101516040517f19d5c79b000000000000000000000000000000000000000000000000000000008152600401610f7991907fffffffffffffffffffffffffffffffff0000000000000000000000000000000091909116815260200190565b600101610ff0565b507f1716e663a90a76d3b6c7e5f680673d1b051454c19c627e184c8daf28f3104f7481604051610fba9190611891565b60015473ffffffffffffffffffffffffffffffffffffffff163314611128576040517f2b5c74de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b6000610841825490565b7fffffffffffffffffffffffffffffffff000000000000000000000000000000008116600090815260018301602052604081205415155b9392505050565b600061116b837fffffffffffffffffffffffffffffffff00000000000000000000000000000000841661129f565b6060600061116b83611399565b3373ffffffffffffffffffffffffffffffffffffffff8216036111fc576040517fdad89dca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217835560015460405192939116917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600061116b837fffffffffffffffffffffffffffffffff0000000000000000000000000000000084166113f5565b600081815260018301602052604081205480156113885760006112c3600183611a18565b85549091506000906112d790600190611a18565b905080821461133c5760008660000182815481106112f7576112f761197c565b906000526020600020015490508087600001848154811061131a5761131a61197c565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061134d5761134d6120be565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610841565b6000915050610841565b5092915050565b6060816000018054806020026020016040519081016040528092919081815260200182805480156113e957602002820191906000526020600020905b8154815260200190600101908083116113d5575b50505050509050919050565b600081815260018301602052604081205461143c57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610841565b506000610841565b6000815180845260005b8181101561146a5760208185018101518683018201520161144e565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061116b6020830184611444565b6000602082840312156114cd57600080fd5b813567ffffffffffffffff8111156114e457600080fd5b82016060818503121561116b57600080fd5b63ffffffff831681526040602080830182905283518383015283810151606080850152805160a085018190526000939291820190849060c08701905b8083101561157b578351805173ffffffffffffffffffffffffffffffffffffffff16835285015167ffffffffffffffff1685830152928401926001929092019190850190611532565b50604088015167ffffffffffffffff81166080890152945098975050505050505050565b80357fffffffffffffffffffffffffffffffff00000000000000000000000000000000811681146115cf57600080fd5b919050565b6000602082840312156115e657600080fd5b61116b8261159f565b60006040828403121561160157600080fd5b50919050565b73ffffffffffffffffffffffffffffffffffffffff81168114610fe257600080fd5b60008083601f84011261163b57600080fd5b50813567ffffffffffffffff81111561165357600080fd5b6020830191508360208260061b850101111561166e57600080fd5b9250929050565b60008060008060006060868803121561168d57600080fd5b853561169881611607565b9450602086013567ffffffffffffffff808211156116b557600080fd5b818801915088601f8301126116c957600080fd5b8135818111156116d857600080fd5b8960208260051b85010111156116ed57600080fd5b60208301965080955050604088013591508082111561170b57600080fd5b5061171888828901611629565b969995985093965092949392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff8111828210171561177b5761177b611729565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156117c8576117c8611729565b604052919050565b600067ffffffffffffffff8211156117ea576117ea611729565b5060051b60200190565b6000602080838503121561180757600080fd5b823567ffffffffffffffff81111561181e57600080fd5b8301601f8101851361182f57600080fd5b803561184261183d826117d0565b611781565b81815260059190911b8201830190838101908783111561186157600080fd5b928401925b82841015611886576118778461159f565b82529284019290840190611866565b979650505050505050565b6020808252825182820181905260009190848201906040850190845b818110156118eb5783517fffffffffffffffffffffffffffffffff0000000000000000000000000000000016835292840192918401916001016118ad565b50909695505050505050565b60006020828403121561190957600080fd5b813561116b81611607565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261194957600080fd5b83018035915067ffffffffffffffff82111561196457600080fd5b6020019150600681901b360382131561166e57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b67ffffffffffffffff81168114610fe257600080fd5b80356115cf816119ab565b6000602082840312156119de57600080fd5b813561116b816119ab565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610841576108416119e9565b67ffffffffffffffff818116838216028082169190828114611a4f57611a4f6119e9565b505092915050565b67ffffffffffffffff818116838216019080821115611392576113926119e9565b600081611a8757611a876119e9565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b60008135610841816119ab565b8135611ac581611607565b73ffffffffffffffffffffffffffffffffffffffff811690508154817fffffffffffffffffffffffff000000000000000000000000000000000000000082161783556020840135611b15816119ab565b7bffffffffffffffff00000000000000000000000000000000000000008160a01b16837fffffffff000000000000000000000000000000000000000000000000000000008416171784555050505050565b81358155600180820160208401357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1853603018112611ba457600080fd5b8401803567ffffffffffffffff811115611bbd57600080fd5b6020820191508060061b3603821315611bd557600080fd5b68010000000000000000811115611bee57611bee611729565b825481845580821015611c23576000848152602081208381019083015b80821015611c1f5782825590870190611c0b565b5050505b50600092835260208320925b81811015611c5357611c418385611aba565b92840192604092909201918401611c2f565b5050505050610a22611c6760408401611aad565b6002830167ffffffffffffffff82167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008254161781555050565b600063ffffffff808316818103611cba57611cba6119e9565b6001019392505050565b6000602080835260808301843582850152818501357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1863603018112611d0957600080fd5b8501828101903567ffffffffffffffff80821115611d2657600080fd5b8160061b3603831315611d3857600080fd5b6040606060408901528483865260a089019050849550600094505b83851015611da3578535611d6681611607565b73ffffffffffffffffffffffffffffffffffffffff16815285870135611d8b816119ab565b83168188015294810194600194909401938101611d53565b611daf60408b016119c1565b67ffffffffffffffff811660608b015296509998505050505050505050565b604081018235611ddd81611607565b73ffffffffffffffffffffffffffffffffffffffff81168352506020830135602083015292915050565b600060208284031215611e1957600080fd5b8151801515811461116b57600080fd5b6000611e3761183d846117d0565b80848252602080830192508560051b850136811115611e5557600080fd5b855b81811015611f7d57803567ffffffffffffffff80821115611e785760008081fd5b818901915060a08236031215611e8e5760008081fd5b611e96611758565b8235611ea1816119ab565b81528286013582811115611eb55760008081fd5b8301601f3681830112611ec85760008081fd5b813584811115611eda57611eda611729565b611f09897fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08484011601611781565b94508085523689828501011115611f2257600091508182fd5b808984018a8701376000898287010152505050818682015260409150611f498284016119c1565b8282015260609150611f5c8284016119c1565b91810191909152608091820135918101919091528552938201938201611e57565b50919695505050505050565b60006040848352602060408185015261010084018551604086015281860151606067ffffffffffffffff808316606089015260408901519250608073ffffffffffffffffffffffffffffffffffffffff80851660808b015260608b0151945060a081861660a08c015260808c015160c08c015260a08c0151955060c060e08c015286915085518088526101209750878c019250878160051b8d01019750888701965060005b818110156120ab577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee08d8a030184528751868151168a528a810151848c8c015261207a858c0182611444565b828e015189168c8f01528983015189168a8d0152918701519a87019a909a529850968901969289019260010161202e565b50969d9c50505050505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000818000a", } var RMNRemoteABI = RMNRemoteMetaData.ABI diff --git a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt index f35104e20df..95a62aad83b 100644 --- a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -23,7 +23,7 @@ registry_module_owner_custom: ../../../contracts/solc/v0.8.24/RegistryModuleOwne report_codec: ../../../contracts/solc/v0.8.24/ReportCodec/ReportCodec.abi ../../../contracts/solc/v0.8.24/ReportCodec/ReportCodec.bin 6c943b39f003aa67c3cefa19a8ff99e846236a058e1ceae77569c3a065ffd5c7 rmn_home: ../../../contracts/solc/v0.8.24/RMNHome/RMNHome.abi ../../../contracts/solc/v0.8.24/RMNHome/RMNHome.bin 84ca84b3d0c00949905a3d10a91255f877cf32b2a0d7f7f7ce3121ced34a8cb7 rmn_proxy_contract: ../../../contracts/solc/v0.8.24/ARMProxy/ARMProxy.abi ../../../contracts/solc/v0.8.24/ARMProxy/ARMProxy.bin b048d8e752e3c41113ebb305c1efa06737ad36b4907b93e627fb0a3113023454 -rmn_remote: ../../../contracts/solc/v0.8.24/RMNRemote/RMNRemote.abi ../../../contracts/solc/v0.8.24/RMNRemote/RMNRemote.bin 941118dfdc6bb042c339cfe8d8e0c7a0b486afb731a785d58a64994e7a13c459 +rmn_remote: ../../../contracts/solc/v0.8.24/RMNRemote/RMNRemote.abi ../../../contracts/solc/v0.8.24/RMNRemote/RMNRemote.bin 2bf58225d1ceec21f3dd9e65b8088945c643ec527ae54b9983ec46316f5bca1f router: ../../../contracts/solc/v0.8.24/Router/Router.abi ../../../contracts/solc/v0.8.24/Router/Router.bin 2e4f0a7826c8abb49d882bb49fc5ff20a186dbd3137624b9097ffed903ae4888 token_admin_registry: ../../../contracts/solc/v0.8.24/TokenAdminRegistry/TokenAdminRegistry.abi ../../../contracts/solc/v0.8.24/TokenAdminRegistry/TokenAdminRegistry.bin 397bc7be08c2848c0f4715f90b16206d6367f78ffb7cd48e2b1dfc0ccc5aea26 token_pool: ../../../contracts/solc/v0.8.24/TokenPool/TokenPool.abi ../../../contracts/solc/v0.8.24/TokenPool/TokenPool.bin 793d65f336929becdcf8bc3f2208a5b6de93774215fe2e863bef64df419cfdb0 From a5b177ffd5598c201d76752a4f0fa90dee375d71 Mon Sep 17 00:00:00 2001 From: nogo <110664798+0xnogo@users.noreply.github.com> Date: Tue, 17 Dec 2024 17:45:21 +0400 Subject: [PATCH 02/27] Re-enable fee boosting integration test (#15704) * re-enable * more comments --- .../smoke/ccip/ccip_fee_boosting_test.go | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/integration-tests/smoke/ccip/ccip_fee_boosting_test.go b/integration-tests/smoke/ccip/ccip_fee_boosting_test.go index 48d9061ec63..576ee356fbb 100644 --- a/integration-tests/smoke/ccip/ccip_fee_boosting_test.go +++ b/integration-tests/smoke/ccip/ccip_fee_boosting_test.go @@ -9,6 +9,7 @@ import ( "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/config" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" @@ -17,7 +18,6 @@ import ( "github.com/test-go/testify/require" "golang.org/x/exp/maps" - "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/ccipevm" @@ -39,20 +39,17 @@ var ( func Test_CCIPFeeBoosting(t *testing.T) { e, _ := testsetups.NewIntegrationEnvironment( t, - // TODO check if test should use these overrides - /* changeset.WithOCRConfigOverride(func(params changeset.CCIPOCRParams) changeset.CCIPOCRParams { - // Only 1 boost (=OCR round) is enough to cover the fee - params.ExecuteOffChainConfig.RelativeBoostPerWaitHour = 10 - // Disable token price updates - params.CommitOffChainConfig.TokenPriceBatchWriteFrequency = *config.MustNewDuration(1_000_000 * time.Hour) - // Disable gas price updates - params.CommitOffChainConfig.RemoteGasPriceBatchWriteFrequency = *config.MustNewDuration(1_000_000 * time.Hour) - // Disable token price updates - params.CommitOffChainConfig.TokenInfo = nil - return params - }), - - */ + changeset.WithOCRConfigOverride(func(params changeset.CCIPOCRParams) changeset.CCIPOCRParams { + // Only 1 boost (=OCR round) is enough to cover the fee + params.ExecuteOffChainConfig.RelativeBoostPerWaitHour = 10 + // Disable token price updates + params.CommitOffChainConfig.TokenPriceBatchWriteFrequency = *config.MustNewDuration(1_000_000 * time.Hour) + // Disable gas price updates + params.CommitOffChainConfig.RemoteGasPriceBatchWriteFrequency = *config.MustNewDuration(1_000_000 * time.Hour) + // Disable token price updates + params.CommitOffChainConfig.TokenInfo = nil + return params + }), ) state, err := changeset.LoadOnchainState(e.Env) @@ -69,7 +66,9 @@ func Test_CCIPFeeBoosting(t *testing.T) { ", dest chain selector:", destChain, ) - fetchedGasPriceDest, err := e.Env.Chains[destChain].Client.SuggestGasPrice(tests.Context(t)) + // TODO: discrepancy between client and the gas estimator gas price to be fixed - hardcoded for now + // fetchedGasPriceDest, err := e.Env.Chains[destChain].Client.SuggestGasPrice(tests.Context(t)) + fetchedGasPriceDest := big.NewInt(20e9) // 20 Gwei = default gas price require.NoError(t, err) originalGasPriceDestUSD := new(big.Int).Div( new(big.Int).Mul(fetchedGasPriceDest, wethPrice), From 85557450c00c7c00d9dd047fa8a4ccd0dfb12631 Mon Sep 17 00:00:00 2001 From: msuchacz-cll <170782674+msuchacz-cll@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:02:28 +0100 Subject: [PATCH 03/27] mercury transmitter bugfix (#15733) --- core/services/relay/evm/mercury/transmitter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go index bdd324988bf..745eb1db646 100644 --- a/core/services/relay/evm/mercury/transmitter.go +++ b/core/services/relay/evm/mercury/transmitter.go @@ -236,7 +236,7 @@ func (s *server) runQueueLoop(stopCh services.StopChan, wg *sync.WaitGroup, feed } res, err := func(ctx context.Context) (*pb.TransmitResponse, error) { ctx, cancel := context.WithTimeout(ctx, utils.WithJitter(s.transmitTimeout)) - cancel() + defer cancel() return s.c.Transmit(ctx, t.Req) }(ctx) if ctx.Err() != nil { From fd9d5de76f4d86555472c21fb184ebaa82b143b7 Mon Sep 17 00:00:00 2001 From: Graham Goh Date: Wed, 18 Dec 2024 02:25:55 +1100 Subject: [PATCH 04/27] refactor(mcms): handle nil scenario (#15725) Some scenarios will throw nil pointer exception without using the ok pattern check. We should handle those properly. --- .../transfer_to_mcms_with_timelock.go | 42 ++++++++-- .../transfer_to_mcms_with_timelock_test.go | 77 +++++++++++++++++++ 2 files changed, 113 insertions(+), 6 deletions(-) diff --git a/deployment/common/changeset/transfer_to_mcms_with_timelock.go b/deployment/common/changeset/transfer_to_mcms_with_timelock.go index afba1afa48b..45efccefd2e 100644 --- a/deployment/common/changeset/transfer_to_mcms_with_timelock.go +++ b/deployment/common/changeset/transfer_to_mcms_with_timelock.go @@ -218,25 +218,55 @@ type RenounceTimelockDeployerConfig struct { ChainSel uint64 } +func (cfg RenounceTimelockDeployerConfig) Validate(e deployment.Environment) error { + if err := deployment.IsValidChainSelector(cfg.ChainSel); err != nil { + return fmt.Errorf("invalid chain selector: %w", err) + } + + _, ok := e.Chains[cfg.ChainSel] + if !ok { + return fmt.Errorf("chain selector: %d not found in environment", cfg.ChainSel) + } + + // MCMS should already exists + state, err := MaybeLoadMCMSWithTimelockState(e, []uint64{cfg.ChainSel}) + if err != nil { + return err + } + + contract, ok := state[cfg.ChainSel] + if !ok { + return fmt.Errorf("mcms contracts not found on chain %d", cfg.ChainSel) + } + if contract.Timelock == nil { + return fmt.Errorf("timelock not found on chain %d", cfg.ChainSel) + } + + return nil +} + // RenounceTimelockDeployer revokes the deployer key from administering the contract. func RenounceTimelockDeployer(e deployment.Environment, cfg RenounceTimelockDeployerConfig) (deployment.ChangesetOutput, error) { + if err := cfg.Validate(e); err != nil { + return deployment.ChangesetOutput{}, err + } + contracts, err := MaybeLoadMCMSWithTimelockState(e, []uint64{cfg.ChainSel}) if err != nil { return deployment.ChangesetOutput{}, err } tl := contracts[cfg.ChainSel].Timelock - if tl == nil { - return deployment.ChangesetOutput{}, fmt.Errorf("timelock not found on chain %d", cfg.ChainSel) - } - admin, err := tl.ADMINROLE(&bind.CallOpts{}) + admin, err := tl.ADMINROLE(&bind.CallOpts{Context: e.GetContext()}) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to get admin role: %w", err) } - tx, err := tl.RenounceRole(e.Chains[cfg.ChainSel].DeployerKey, admin, e.Chains[cfg.ChainSel].DeployerKey.From) + + chain := e.Chains[cfg.ChainSel] + tx, err := tl.RenounceRole(chain.DeployerKey, admin, chain.DeployerKey.From) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to revoke deployer key: %w", err) } - if _, err := deployment.ConfirmIfNoError(e.Chains[cfg.ChainSel], tx, err); err != nil { + if _, err := deployment.ConfirmIfNoError(chain, tx, err); err != nil { return deployment.ChangesetOutput{}, err } e.Logger.Infof("revoked deployer key from owning contract %s", tl.Address().Hex()) diff --git a/deployment/common/changeset/transfer_to_mcms_with_timelock_test.go b/deployment/common/changeset/transfer_to_mcms_with_timelock_test.go index 49c46aab5f0..c8c0f462811 100644 --- a/deployment/common/changeset/transfer_to_mcms_with_timelock_test.go +++ b/deployment/common/changeset/transfer_to_mcms_with_timelock_test.go @@ -6,8 +6,10 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + chain_selectors "github.com/smartcontractkit/chain-selectors" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" "github.com/smartcontractkit/chainlink/deployment/common/types" "github.com/smartcontractkit/chainlink/deployment/environment/memory" @@ -81,6 +83,81 @@ func TestTransferToMCMSWithTimelock(t *testing.T) { require.Equal(t, e.Chains[chain1].DeployerKey.From, o) } +func TestRenounceTimelockDeployerConfigValidate(t *testing.T) { + t.Parallel() + lggr := logger.TestLogger(t) + e := memory.NewMemoryEnvironment(t, lggr, 0, memory.MemoryEnvironmentConfig{ + Chains: 1, + Nodes: 1, + }) + chain1 := e.AllChainSelectors()[0] + e, err := ApplyChangesets(t, e, nil, []ChangesetApplication{ + { + Changeset: WrapChangeSet(DeployMCMSWithTimelock), + Config: map[uint64]types.MCMSWithTimelockConfig{ + chain1: proposalutils.SingleGroupTimelockConfig(t), + }, + }, + }) + require.NoError(t, err) + + envWithNoMCMS := memory.NewMemoryEnvironment(t, lggr, 0, memory.MemoryEnvironmentConfig{ + Chains: 1, + Nodes: 1, + }) + chain2 := envWithNoMCMS.AllChainSelectors()[0] + + for _, test := range []struct { + name string + config RenounceTimelockDeployerConfig + env deployment.Environment + err string + }{ + { + name: "valid config", + env: e, + config: RenounceTimelockDeployerConfig{ + ChainSel: chain1, + }, + }, + { + name: "invalid chain selector", + env: e, + config: RenounceTimelockDeployerConfig{ + ChainSel: 0, + }, + err: "invalid chain selector: chain selector must be set", + }, + { + name: "chain does not exists on env", + env: e, + config: RenounceTimelockDeployerConfig{ + ChainSel: chain_selectors.ETHEREUM_TESTNET_SEPOLIA.Selector, + }, + err: "chain selector: 16015286601757825753 not found in environment", + }, + { + name: "no MCMS deployed", + env: envWithNoMCMS, + config: RenounceTimelockDeployerConfig{ + ChainSel: chain2, + }, + // chain does not match any existing addresses + err: "chain selector 909606746561742123: chain not found", + }, + } { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + err := test.config.Validate(test.env) + if test.err != "" { + require.EqualError(t, err, test.err) + } else { + require.NoError(t, err) + } + }) + } +} + func TestRenounceTimelockDeployer(t *testing.T) { lggr := logger.TestLogger(t) e := memory.NewMemoryEnvironment(t, lggr, 0, memory.MemoryEnvironmentConfig{ From 45fcad7b3ec9d2d1f085c8cab89542e9a53b6fc2 Mon Sep 17 00:00:00 2001 From: "Simon B.Robert" Date: Tue, 17 Dec 2024 10:58:53 -0500 Subject: [PATCH 05/27] Bump RMNv2 images version in e2e tests (#15736) * Bump RMNv2 images version in e2e tests * Fix image name --- .github/e2e-tests.yml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/e2e-tests.yml b/.github/e2e-tests.yml index 675fa315dfa..142c7733533 100644 --- a/.github/e2e-tests.yml +++ b/.github/e2e-tests.yml @@ -977,8 +977,8 @@ runner-test-matrix: test_env_vars: E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2 E2E_JD_VERSION: 0.6.0 - E2E_RMN_RAGEPROXY_VERSION: master-f461a9e - E2E_RMN_AFN2PROXY_VERSION: master-f461a9e + E2E_RMN_RAGEPROXY_VERSION: 678509b + E2E_RMN_AFN2PROXY_VERSION: 678509b CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_rmn_test.go:^TestRMN_MultipleMessagesOnOneLaneNoWaitForExec$ @@ -993,8 +993,8 @@ runner-test-matrix: test_env_vars: E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2 E2E_JD_VERSION: 0.6.0 - E2E_RMN_RAGEPROXY_VERSION: master-f461a9e - E2E_RMN_AFN2PROXY_VERSION: master-f461a9e + E2E_RMN_RAGEPROXY_VERSION: 678509b + E2E_RMN_AFN2PROXY_VERSION: 678509b CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_rmn_test.go:^TestRMN_NotEnoughObservers$ @@ -1009,8 +1009,8 @@ runner-test-matrix: test_env_vars: E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2 E2E_JD_VERSION: 0.6.0 - E2E_RMN_RAGEPROXY_VERSION: master-f461a9e - E2E_RMN_AFN2PROXY_VERSION: master-f461a9e + E2E_RMN_RAGEPROXY_VERSION: 678509b + E2E_RMN_AFN2PROXY_VERSION: 678509b CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_rmn_test.go:^TestRMN_DifferentSigners$ @@ -1025,8 +1025,8 @@ runner-test-matrix: test_env_vars: E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2 E2E_JD_VERSION: 0.6.0 - E2E_RMN_RAGEPROXY_VERSION: master-f461a9e - E2E_RMN_AFN2PROXY_VERSION: master-f461a9e + E2E_RMN_RAGEPROXY_VERSION: 678509b + E2E_RMN_AFN2PROXY_VERSION: 678509b CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_rmn_test.go:^TestRMN_NotEnoughSigners$ @@ -1041,8 +1041,8 @@ runner-test-matrix: test_env_vars: E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2 E2E_JD_VERSION: 0.6.0 - E2E_RMN_RAGEPROXY_VERSION: master-f461a9e - E2E_RMN_AFN2PROXY_VERSION: master-f461a9e + E2E_RMN_RAGEPROXY_VERSION: 678509b + E2E_RMN_AFN2PROXY_VERSION: 678509b CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_rmn_test.go:^TestRMN_DifferentRmnNodesForDifferentChains$ @@ -1057,8 +1057,8 @@ runner-test-matrix: test_env_vars: E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2 E2E_JD_VERSION: 0.6.0 - E2E_RMN_RAGEPROXY_VERSION: master-f461a9e - E2E_RMN_AFN2PROXY_VERSION: master-f461a9e + E2E_RMN_RAGEPROXY_VERSION: 678509b + E2E_RMN_AFN2PROXY_VERSION: 678509b CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_rmn_test.go:^TestRMN_TwoMessagesOneSourceChainCursed$ @@ -1073,8 +1073,8 @@ runner-test-matrix: test_env_vars: E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2 E2E_JD_VERSION: 0.6.0 - E2E_RMN_RAGEPROXY_VERSION: master-f461a9e - E2E_RMN_AFN2PROXY_VERSION: master-f461a9e + E2E_RMN_RAGEPROXY_VERSION: 678509b + E2E_RMN_AFN2PROXY_VERSION: 678509b CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_rmn_test.go:^TestRMN_GlobalCurseTwoMessagesOnTwoLanes$ @@ -1089,8 +1089,8 @@ runner-test-matrix: test_env_vars: E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2 E2E_JD_VERSION: 0.6.0 - E2E_RMN_RAGEPROXY_VERSION: master-f461a9e - E2E_RMN_AFN2PROXY_VERSION: master-f461a9e + E2E_RMN_RAGEPROXY_VERSION: 678509b + E2E_RMN_AFN2PROXY_VERSION: 678509b CCIP_V16_TEST_ENV: docker # END: CCIPv1.6 tests From 631cd8fae34c73801e223f9ef96f23a032cf407f Mon Sep 17 00:00:00 2001 From: Suryansh <39276431+0xsuryansh@users.noreply.github.com> Date: Tue, 17 Dec 2024 21:36:23 +0530 Subject: [PATCH 06/27] CCIP-4646 account for token transfer bytes overhead in execution cost (#15737) * CCIP-4646 Account for tokenTransferBytesOverhead in exec cost * add changeset * [Bot] Update changeset file with jira issues --------- Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com> --- contracts/.changeset/early-cups-relax.md | 9 ++++ contracts/gas-snapshots/ccip.gas-snapshot | 54 +++++++++---------- contracts/src/v0.8/ccip/FeeQuoter.sol | 3 +- .../feeQuoter/FeeQuoter.getValidatedFee.t.sol | 18 +++++-- .../ccip/generated/fee_quoter/fee_quoter.go | 2 +- ...rapper-dependency-versions-do-not-edit.txt | 2 +- 6 files changed, 53 insertions(+), 35 deletions(-) create mode 100644 contracts/.changeset/early-cups-relax.md diff --git a/contracts/.changeset/early-cups-relax.md b/contracts/.changeset/early-cups-relax.md new file mode 100644 index 00000000000..1ec6aaba0b7 --- /dev/null +++ b/contracts/.changeset/early-cups-relax.md @@ -0,0 +1,9 @@ +--- +'@chainlink/contracts': minor +--- + +#internal Account for tokenTransferBytesOverhead in exec cost + +PR issue: CCIP-4646 + +Solidity Review issue: CCIP-3966 \ No newline at end of file diff --git a/contracts/gas-snapshots/ccip.gas-snapshot b/contracts/gas-snapshots/ccip.gas-snapshot index 147783b52cb..27282f474ce 100644 --- a/contracts/gas-snapshots/ccip.gas-snapshot +++ b/contracts/gas-snapshots/ccip.gas-snapshot @@ -20,7 +20,7 @@ BurnWithFromMintTokenPool_lockOrBurn:test_ChainNotAllowed_Revert() (gas: 27346) BurnWithFromMintTokenPool_lockOrBurn:test_PoolBurnRevertNotHealthy_Revert() (gas: 54878) BurnWithFromMintTokenPool_lockOrBurn:test_PoolBurn_Success() (gas: 244496) BurnWithFromMintTokenPool_lockOrBurn:test_Setup_Success() (gas: 24223) -CCIPClientExample_sanity:test_ImmutableExamples_Success() (gas: 2077779) +CCIPClientExample_sanity:test_ImmutableExamples_Success() (gas: 2078199) CCIPHome__validateConfig:test__validateConfigLessTransmittersThanSigners_Success() (gas: 332619) CCIPHome__validateConfig:test__validateConfigSmallerFChain_Success() (gas: 458568) CCIPHome__validateConfig:test__validateConfig_ABIEncodedAddress_OfframpAddressCannotBeZero_Reverts() (gas: 289191) @@ -68,7 +68,7 @@ CCIPHome_setCandidate:test_setCandidate_success() (gas: 1365439) CCIPHome_supportsInterface:test_supportsInterface_success() (gas: 9885) DefensiveExampleTest:test_HappyPath_Success() (gas: 200540) DefensiveExampleTest:test_Recovery() (gas: 425013) -E2E:test_E2E_3MessagesMMultiOffRampSuccess_gas() (gas: 1512391) +E2E:test_E2E_3MessagesMMultiOffRampSuccess_gas() (gas: 1512665) EtherSenderReceiverTest_ccipReceive:test_ccipReceive_fallbackToWethTransfer() (gas: 96980) EtherSenderReceiverTest_ccipReceive:test_ccipReceive_happyPath() (gas: 49812) EtherSenderReceiverTest_ccipReceive:test_ccipReceive_wrongToken() (gas: 17479) @@ -138,7 +138,7 @@ FeeQuoter_applyTokenTransferFeeConfigUpdates:test_OnlyCallableByOwnerOrAdmin_Rev FeeQuoter_constructor:test_InvalidLinkTokenEqZeroAddress_Revert() (gas: 106632) FeeQuoter_constructor:test_InvalidMaxFeeJuelsPerMsg_Revert() (gas: 110982) FeeQuoter_constructor:test_InvalidStalenessThreshold_Revert() (gas: 111057) -FeeQuoter_constructor:test_Setup_Success() (gas: 5011219) +FeeQuoter_constructor:test_Setup_Success() (gas: 5014619) FeeQuoter_convertTokenAmount:test_ConvertTokenAmount_Success() (gas: 68416) FeeQuoter_convertTokenAmount:test_LinkTokenNotSupported_Revert() (gas: 29300) FeeQuoter_getDataAvailabilityCost:test_EmptyMessageCalculatesDataAvailabilityCost_Success() (gas: 96433) @@ -162,17 +162,17 @@ FeeQuoter_getTokenTransferCost:test_ZeroAmountTokenTransferChargesMinFeeAndGas_S FeeQuoter_getTokenTransferCost:test_ZeroFeeConfigChargesMinFee_Success() (gas: 40822) FeeQuoter_getTokenTransferCost:test_getTokenTransferCost_selfServeUsesDefaults_Success() (gas: 29736) FeeQuoter_getValidatedFee:test_DestinationChainNotEnabled_Revert() (gas: 18465) -FeeQuoter_getValidatedFee:test_EmptyMessage_Success() (gas: 83340) +FeeQuoter_getValidatedFee:test_EmptyMessage_Success() (gas: 83484) FeeQuoter_getValidatedFee:test_EnforceOutOfOrder_Revert() (gas: 53570) -FeeQuoter_getValidatedFee:test_HighGasMessage_Success() (gas: 239736) +FeeQuoter_getValidatedFee:test_HighGasMessage_Success() (gas: 239880) 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: 143246) +FeeQuoter_getValidatedFee:test_MessageWithDataAndTokenTransfer_Success() (gas: 143562) FeeQuoter_getValidatedFee:test_NotAFeeToken_Revert() (gas: 21280) -FeeQuoter_getValidatedFee:test_SingleTokenMessage_Success() (gas: 114510) +FeeQuoter_getValidatedFee:test_SingleTokenMessage_Success() (gas: 115060) FeeQuoter_getValidatedFee:test_TooManyTokens_Revert() (gas: 23495) -FeeQuoter_getValidatedFee:test_ZeroDataAvailabilityMultiplier_Success() (gas: 63909) +FeeQuoter_getValidatedFee:test_ZeroDataAvailabilityMultiplier_Success() (gas: 63981) FeeQuoter_getValidatedTokenPrice:test_GetValidatedTokenPriceFromFeedErc20Above18Decimals_Success() (gas: 1897852) FeeQuoter_getValidatedTokenPrice:test_GetValidatedTokenPriceFromFeedErc20Below18Decimals_Success() (gas: 1897810) FeeQuoter_getValidatedTokenPrice:test_GetValidatedTokenPriceFromFeedFeedAt0Decimals_Success() (gas: 1877929) @@ -491,7 +491,7 @@ OffRamp_trialExecute:test_trialExecute() (gas: 271859) OffRamp_trialExecute:test_trialExecute_RateLimitError() (gas: 127545) OffRamp_trialExecute:test_trialExecute_TokenHandlingErrorIsCaught() (gas: 138855) OffRamp_trialExecute:test_trialExecute_TokenPoolIsNotAContract() (gas: 289500) -OnRampTokenPoolReentrancy:test_OnRampTokenPoolReentrancy_Success() (gas: 251641) +OnRampTokenPoolReentrancy:test_OnRampTokenPoolReentrancy_Success() (gas: 251893) OnRamp_applyAllowlistUpdates:test_applyAllowlistUpdates_InvalidAllowListRequestDisabledAllowListWithAdds() (gas: 17227) OnRamp_applyAllowlistUpdates:test_applyAllowlistUpdates_Revert() (gas: 67101) OnRamp_applyAllowlistUpdates:test_applyAllowlistUpdates_Success() (gas: 325983) @@ -526,11 +526,11 @@ OnRamp_forwardFromRouter:test_UnAllowedOriginalSender_Revert() (gas: 24015) OnRamp_forwardFromRouter:test_UnsupportedToken_Revert() (gas: 75854) OnRamp_forwardFromRouter:test_forwardFromRouter_UnsupportedToken_Revert() (gas: 38588) OnRamp_forwardFromRouter:test_forwardFromRouter_WithInterception_Success() (gas: 281529) -OnRamp_getFee:test_EmptyMessage_Success() (gas: 98692) +OnRamp_getFee:test_EmptyMessage_Success() (gas: 99028) OnRamp_getFee:test_EnforceOutOfOrder_Revert() (gas: 65475) -OnRamp_getFee:test_GetFeeOfZeroForTokenMessage_Success() (gas: 87119) +OnRamp_getFee:test_GetFeeOfZeroForTokenMessage_Success() (gas: 87287) OnRamp_getFee:test_NotAFeeTokenButPricedToken_Revert() (gas: 35166) -OnRamp_getFee:test_SingleTokenMessage_Success() (gas: 113865) +OnRamp_getFee:test_SingleTokenMessage_Success() (gas: 114201) OnRamp_getFee:test_Unhealthy_Revert() (gas: 17040) OnRamp_getSupportedTokens:test_GetSupportedTokens_Revert() (gas: 10565) OnRamp_getTokenPool:test_GetTokenPool_Success() (gas: 35405) @@ -541,11 +541,11 @@ OnRamp_setDynamicConfig:test_setDynamicConfig_InvalidConfigOnlyOwner_Revert() (g OnRamp_setDynamicConfig:test_setDynamicConfig_InvalidConfigReentrancyGuardEnteredEqTrue_Revert() (gas: 13264) OnRamp_setDynamicConfig:test_setDynamicConfig_Success() (gas: 56440) OnRamp_withdrawFeeTokens:test_WithdrawFeeTokens_Success() (gas: 125901) -PingPong_ccipReceive:test_CcipReceive_Success() (gas: 172880) +PingPong_ccipReceive:test_CcipReceive_Success() (gas: 172964) PingPong_setOutOfOrderExecution:test_OutOfOrderExecution_Success() (gas: 20283) PingPong_setPaused:test_Pausing_Success() (gas: 17738) -PingPong_startPingPong:test_StartPingPong_With_OOO_Success() (gas: 151993) -PingPong_startPingPong:test_StartPingPong_With_Sequenced_Ordered_Success() (gas: 177608) +PingPong_startPingPong:test_StartPingPong_With_OOO_Success() (gas: 152077) +PingPong_startPingPong:test_StartPingPong_With_Sequenced_Ordered_Success() (gas: 177692) RMNHome_getConfigDigests:test_getConfigDigests_success() (gas: 1079685) RMNHome_promoteCandidateAndRevokeActive:test_promoteCandidateAndRevokeActive_ConfigDigestMismatch_reverts() (gas: 23879) RMNHome_promoteCandidateAndRevokeActive:test_promoteCandidateAndRevokeActive_NoOpStateTransitionNotAllowed_reverts() (gas: 10597) @@ -612,23 +612,23 @@ RegistryModuleOwnerCustom_registerAdminViaOwner:test_registerAdminViaOwner_Rever RegistryModuleOwnerCustom_registerAdminViaOwner:test_registerAdminViaOwner_Success() (gas: 129930) Router_applyRampUpdates:test_applyRampUpdates_OffRampUpdatesWithRouting() (gas: 10749731) Router_applyRampUpdates:test_applyRampUpdates_OnRampDisable() (gas: 56422) -Router_ccipSend:test_CCIPSendLinkFeeNoTokenSuccess_gas() (gas: 131447) -Router_ccipSend:test_CCIPSendLinkFeeOneTokenSuccess_gas() (gas: 221710) -Router_ccipSend:test_FeeTokenAmountTooLow_Revert() (gas: 71858) +Router_ccipSend:test_CCIPSendLinkFeeNoTokenSuccess_gas() (gas: 131531) +Router_ccipSend:test_CCIPSendLinkFeeOneTokenSuccess_gas() (gas: 221794) +Router_ccipSend:test_FeeTokenAmountTooLow_Revert() (gas: 71942) Router_ccipSend:test_InvalidMsgValue() (gas: 32411) -Router_ccipSend:test_NativeFeeTokenInsufficientValue() (gas: 69524) -Router_ccipSend:test_NativeFeeTokenOverpay_Success() (gas: 193318) -Router_ccipSend:test_NativeFeeTokenZeroValue() (gas: 61550) -Router_ccipSend:test_NativeFeeToken_Success() (gas: 191922) -Router_ccipSend:test_NonLinkFeeToken_Success() (gas: 226583) +Router_ccipSend:test_NativeFeeTokenInsufficientValue() (gas: 69608) +Router_ccipSend:test_NativeFeeTokenOverpay_Success() (gas: 193486) +Router_ccipSend:test_NativeFeeTokenZeroValue() (gas: 61634) +Router_ccipSend:test_NativeFeeToken_Success() (gas: 192090) +Router_ccipSend:test_NonLinkFeeToken_Success() (gas: 226667) Router_ccipSend:test_UnsupportedDestinationChain_Revert() (gas: 25056) Router_ccipSend:test_WhenNotHealthy_Revert() (gas: 45056) -Router_ccipSend:test_WrappedNativeFeeToken_Success() (gas: 194231) -Router_ccipSend:test_ccipSend_nativeFeeNoTokenSuccess_gas() (gas: 140696) -Router_ccipSend:test_ccipSend_nativeFeeOneTokenSuccess_gas() (gas: 230894) +Router_ccipSend:test_WrappedNativeFeeToken_Success() (gas: 194399) +Router_ccipSend:test_ccipSend_nativeFeeNoTokenSuccess_gas() (gas: 140780) +Router_ccipSend:test_ccipSend_nativeFeeOneTokenSuccess_gas() (gas: 230978) Router_constructor:test_Constructor_Success() (gas: 13222) Router_getArmProxy:test_getArmProxy() (gas: 10573) -Router_getFee:test_GetFeeSupportedChain_Success() (gas: 51934) +Router_getFee:test_GetFeeSupportedChain_Success() (gas: 52018) Router_getFee:test_UnsupportedDestinationChain_Revert() (gas: 17385) Router_getSupportedTokens:test_GetSupportedTokens_Revert() (gas: 10565) Router_recoverTokens:test_RecoverTokensInvalidRecipient_Revert() (gas: 11410) diff --git a/contracts/src/v0.8/ccip/FeeQuoter.sol b/contracts/src/v0.8/ccip/FeeQuoter.sol index b312e732e61..d54520c096f 100644 --- a/contracts/src/v0.8/ccip/FeeQuoter.sol +++ b/contracts/src/v0.8/ccip/FeeQuoter.sol @@ -600,7 +600,8 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver, // fee logic for other chains should be implemented in the future. uint256 executionCost = uint112(packedGasPrice) * ( - destChainConfig.destGasOverhead + (message.data.length * destChainConfig.destGasPerPayloadByte) + tokenTransferGas + destChainConfig.destGasOverhead + + ((message.data.length + tokenTransferBytesOverhead) * destChainConfig.destGasPerPayloadByte) + tokenTransferGas + _parseEVMExtraArgsFromBytes(message.extraArgs, destChainConfig).gasLimit ) * destChainConfig.gasMultiplierWeiPerEth; 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 1f76f3120ae..c8912b38e74 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 @@ -103,7 +103,7 @@ contract FeeQuoter_getValidatedFee is FeeQuoterFeeSetup { uint256 feeAmount = s_feeQuoter.getValidatedFee(DEST_CHAIN_SELECTOR, message); - uint256 gasUsed = GAS_LIMIT + DEST_GAS_OVERHEAD + uint256 gasUsed = GAS_LIMIT + DEST_GAS_OVERHEAD + tokenBytesOverhead * DEST_GAS_PER_PAYLOAD_BYTE + s_feeQuoter.getTokenTransferFeeConfig(DEST_CHAIN_SELECTOR, message.tokenAmounts[0].token).destGasOverhead; uint256 gasFeeUSD = (gasUsed * destChainConfig.gasMultiplierWeiPerEth * USD_PER_GAS); (uint256 transferFeeUSD,,) = @@ -152,12 +152,20 @@ contract FeeQuoter_getValidatedFee is FeeQuoterFeeSetup { tokenBytesOverhead += destBytesOverhead == 0 ? uint32(Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) : destBytesOverhead; } - uint256 gasUsed = - customGasLimit + DEST_GAS_OVERHEAD + message.data.length * DEST_GAS_PER_PAYLOAD_BYTE + tokenGasOverhead; - uint256 gasFeeUSD = (gasUsed * destChainConfig.gasMultiplierWeiPerEth * USD_PER_GAS); - (uint256 transferFeeUSD,,) = + (uint256 transferFeeUSD,, uint256 tokenTransferBytesOverhead) = s_feeQuoter.getTokenTransferCost(DEST_CHAIN_SELECTOR, message.feeToken, feeTokenPrices[i], message.tokenAmounts); + + uint256 gasFeeUSD; + + { + uint256 gasUsed = customGasLimit + DEST_GAS_OVERHEAD + + (message.data.length + tokenTransferBytesOverhead) * DEST_GAS_PER_PAYLOAD_BYTE + tokenGasOverhead; + + gasFeeUSD = (gasUsed * destChainConfig.gasMultiplierWeiPerEth * USD_PER_GAS); + } + uint256 messageFeeUSD = (transferFeeUSD * premiumMultiplierWeiPerEth); + uint256 dataAvailabilityFeeUSD = s_feeQuoter.getDataAvailabilityCost( DEST_CHAIN_SELECTOR, USD_PER_DATA_AVAILABILITY_GAS, diff --git a/core/gethwrappers/ccip/generated/fee_quoter/fee_quoter.go b/core/gethwrappers/ccip/generated/fee_quoter/fee_quoter.go index 1f64166ac74..9d667df3498 100644 --- a/core/gethwrappers/ccip/generated/fee_quoter/fee_quoter.go +++ b/core/gethwrappers/ccip/generated/fee_quoter/fee_quoter.go @@ -157,7 +157,7 @@ type KeystoneFeedsPermissionHandlerPermission struct { var FeeQuoterMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"maxFeeJuelsPerMsg\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"tokenPriceStalenessThreshold\",\"type\":\"uint32\"}],\"internalType\":\"structFeeQuoter.StaticConfig\",\"name\":\"staticConfig\",\"type\":\"tuple\"},{\"internalType\":\"address[]\",\"name\":\"priceUpdaters\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"feeTokens\",\"type\":\"address[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"dataFeedAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"tokenDecimals\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"}],\"internalType\":\"structFeeQuoter.TokenPriceFeedConfig\",\"name\":\"feedConfig\",\"type\":\"tuple\"}],\"internalType\":\"structFeeQuoter.TokenPriceFeedUpdate[]\",\"name\":\"tokenPriceFeeds\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"minFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"deciBps\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"}],\"internalType\":\"structFeeQuoter.TokenTransferFeeConfig\",\"name\":\"tokenTransferFeeConfig\",\"type\":\"tuple\"}],\"internalType\":\"structFeeQuoter.TokenTransferFeeConfigSingleTokenArgs[]\",\"name\":\"tokenTransferFeeConfigs\",\"type\":\"tuple[]\"}],\"internalType\":\"structFeeQuoter.TokenTransferFeeConfigArgs[]\",\"name\":\"tokenTransferFeeConfigArgs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"premiumMultiplierWeiPerEth\",\"type\":\"uint64\"}],\"internalType\":\"structFeeQuoter.PremiumMultiplierWeiPerEthArgs[]\",\"name\":\"premiumMultiplierWeiPerEthArgs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"defaultTokenFeeUSDCents\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasPriceStalenessThreshold\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"enforceOutOfOrder\",\"type\":\"bool\"},{\"internalType\":\"bytes4\",\"name\":\"chainFamilySelector\",\"type\":\"bytes4\"}],\"internalType\":\"structFeeQuoter.DestChainConfig\",\"name\":\"destChainConfig\",\"type\":\"tuple\"}],\"internalType\":\"structFeeQuoter.DestChainConfigArgs[]\",\"name\":\"destChainConfigArgs\",\"type\":\"tuple[]\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CannotTransferToSelf\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"DataFeedValueOutOfUint224Range\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"DestinationChainNotEnabled\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ExtraArgOutOfOrderExecutionMustBeTrue\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"FeeTokenNotSupported\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"}],\"name\":\"InvalidDestBytesOverhead\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"InvalidDestChainConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"encodedAddress\",\"type\":\"bytes\"}],\"name\":\"InvalidEVMAddress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidExtraArgsTag\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"minFeeUSDCents\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint256\"}],\"name\":\"InvalidFeeRange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidStaticConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"msgFeeJuels\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxFeeJuelsPerMsg\",\"type\":\"uint256\"}],\"name\":\"MessageFeeTooHigh\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MessageGasLimitTooHigh\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"maxSize\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"actualSize\",\"type\":\"uint256\"}],\"name\":\"MessageTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"MustBeProposedOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OwnerCannotBeZero\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"workflowOwner\",\"type\":\"address\"},{\"internalType\":\"bytes10\",\"name\":\"workflowName\",\"type\":\"bytes10\"},{\"internalType\":\"bytes2\",\"name\":\"reportName\",\"type\":\"bytes2\"}],\"name\":\"ReportForwarderUnauthorized\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"SourceTokenDataTooLarge\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"timePassed\",\"type\":\"uint256\"}],\"name\":\"StaleGasPrice\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"TokenNotSupported\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"UnauthorizedCaller\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"numberOfTokens\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint256\"}],\"name\":\"UnsupportedNumberOfTokens\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"AuthorizedCallerAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"caller\",\"type\":\"address\"}],\"name\":\"AuthorizedCallerRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"defaultTokenFeeUSDCents\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasPriceStalenessThreshold\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"enforceOutOfOrder\",\"type\":\"bool\"},{\"internalType\":\"bytes4\",\"name\":\"chainFamilySelector\",\"type\":\"bytes4\"}],\"indexed\":false,\"internalType\":\"structFeeQuoter.DestChainConfig\",\"name\":\"destChainConfig\",\"type\":\"tuple\"}],\"name\":\"DestChainAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"defaultTokenFeeUSDCents\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasPriceStalenessThreshold\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"enforceOutOfOrder\",\"type\":\"bool\"},{\"internalType\":\"bytes4\",\"name\":\"chainFamilySelector\",\"type\":\"bytes4\"}],\"indexed\":false,\"internalType\":\"structFeeQuoter.DestChainConfig\",\"name\":\"destChainConfig\",\"type\":\"tuple\"}],\"name\":\"DestChainConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"}],\"name\":\"FeeTokenAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"}],\"name\":\"FeeTokenRemoved\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferRequested\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"premiumMultiplierWeiPerEth\",\"type\":\"uint64\"}],\"name\":\"PremiumMultiplierWeiPerEthUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"dataFeedAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"tokenDecimals\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"}],\"indexed\":false,\"internalType\":\"structFeeQuoter.TokenPriceFeedConfig\",\"name\":\"priceFeedConfig\",\"type\":\"tuple\"}],\"name\":\"PriceFeedPerTokenUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"reportId\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"},{\"internalType\":\"bytes10\",\"name\":\"workflowName\",\"type\":\"bytes10\"},{\"internalType\":\"bytes2\",\"name\":\"reportName\",\"type\":\"bytes2\"},{\"internalType\":\"address\",\"name\":\"workflowOwner\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"isAllowed\",\"type\":\"bool\"}],\"indexed\":false,\"internalType\":\"structKeystoneFeedsPermissionHandler.Permission\",\"name\":\"permission\",\"type\":\"tuple\"}],\"name\":\"ReportPermissionSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"TokenTransferFeeConfigDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"minFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"deciBps\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"}],\"indexed\":false,\"internalType\":\"structFeeQuoter.TokenTransferFeeConfig\",\"name\":\"tokenTransferFeeConfig\",\"type\":\"tuple\"}],\"name\":\"TokenTransferFeeConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"UsdPerTokenUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint64\",\"name\":\"destChain\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"name\":\"UsdPerUnitGasUpdated\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"FEE_BASE_DECIMALS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"KEYSTONE_PRICE_DECIMALS\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address[]\",\"name\":\"addedCallers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"removedCallers\",\"type\":\"address[]\"}],\"internalType\":\"structAuthorizedCallers.AuthorizedCallerArgs\",\"name\":\"authorizedCallerArgs\",\"type\":\"tuple\"}],\"name\":\"applyAuthorizedCallerUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"defaultTokenFeeUSDCents\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasPriceStalenessThreshold\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"enforceOutOfOrder\",\"type\":\"bool\"},{\"internalType\":\"bytes4\",\"name\":\"chainFamilySelector\",\"type\":\"bytes4\"}],\"internalType\":\"structFeeQuoter.DestChainConfig\",\"name\":\"destChainConfig\",\"type\":\"tuple\"}],\"internalType\":\"structFeeQuoter.DestChainConfigArgs[]\",\"name\":\"destChainConfigArgs\",\"type\":\"tuple[]\"}],\"name\":\"applyDestChainConfigUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"feeTokensToRemove\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"feeTokensToAdd\",\"type\":\"address[]\"}],\"name\":\"applyFeeTokensUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"premiumMultiplierWeiPerEth\",\"type\":\"uint64\"}],\"internalType\":\"structFeeQuoter.PremiumMultiplierWeiPerEthArgs[]\",\"name\":\"premiumMultiplierWeiPerEthArgs\",\"type\":\"tuple[]\"}],\"name\":\"applyPremiumMultiplierWeiPerEthUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"minFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"deciBps\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"}],\"internalType\":\"structFeeQuoter.TokenTransferFeeConfig\",\"name\":\"tokenTransferFeeConfig\",\"type\":\"tuple\"}],\"internalType\":\"structFeeQuoter.TokenTransferFeeConfigSingleTokenArgs[]\",\"name\":\"tokenTransferFeeConfigs\",\"type\":\"tuple[]\"}],\"internalType\":\"structFeeQuoter.TokenTransferFeeConfigArgs[]\",\"name\":\"tokenTransferFeeConfigArgs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"internalType\":\"structFeeQuoter.TokenTransferFeeConfigRemoveArgs[]\",\"name\":\"tokensToUseDefaultFeeConfigs\",\"type\":\"tuple[]\"}],\"name\":\"applyTokenTransferFeeConfigUpdates\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"fromToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"fromTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"toToken\",\"type\":\"address\"}],\"name\":\"convertTokenAmount\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAllAuthorizedCallers\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"getDestChainConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"},{\"internalType\":\"uint16\",\"name\":\"maxNumberOfTokensPerMsg\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"maxDataBytes\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxPerMsgGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerPayloadByte\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destDataAvailabilityOverheadGas\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"destGasPerDataAvailabilityByte\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"destDataAvailabilityMultiplierBps\",\"type\":\"uint16\"},{\"internalType\":\"uint16\",\"name\":\"defaultTokenFeeUSDCents\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"defaultTokenDestGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"defaultTxGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"gasMultiplierWeiPerEth\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"networkFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasPriceStalenessThreshold\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"enforceOutOfOrder\",\"type\":\"bool\"},{\"internalType\":\"bytes4\",\"name\":\"chainFamilySelector\",\"type\":\"bytes4\"}],\"internalType\":\"structFeeQuoter.DestChainConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"getDestinationChainGasPrice\",\"outputs\":[{\"components\":[{\"internalType\":\"uint224\",\"name\":\"value\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"timestamp\",\"type\":\"uint32\"}],\"internalType\":\"structInternal.TimestampedPackedUint224\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getFeeTokens\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getPremiumMultiplierWeiPerEth\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"premiumMultiplierWeiPerEth\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getStaticConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint96\",\"name\":\"maxFeeJuelsPerMsg\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"linkToken\",\"type\":\"address\"},{\"internalType\":\"uint32\",\"name\":\"tokenPriceStalenessThreshold\",\"type\":\"uint32\"}],\"internalType\":\"structFeeQuoter.StaticConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"}],\"name\":\"getTokenAndGasPrices\",\"outputs\":[{\"internalType\":\"uint224\",\"name\":\"tokenPrice\",\"type\":\"uint224\"},{\"internalType\":\"uint224\",\"name\":\"gasPriceValue\",\"type\":\"uint224\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getTokenPrice\",\"outputs\":[{\"components\":[{\"internalType\":\"uint224\",\"name\":\"value\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"timestamp\",\"type\":\"uint32\"}],\"internalType\":\"structInternal.TimestampedPackedUint224\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getTokenPriceFeedConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"dataFeedAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"tokenDecimals\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"}],\"internalType\":\"structFeeQuoter.TokenPriceFeedConfig\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"tokens\",\"type\":\"address[]\"}],\"name\":\"getTokenPrices\",\"outputs\":[{\"components\":[{\"internalType\":\"uint224\",\"name\":\"value\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"timestamp\",\"type\":\"uint32\"}],\"internalType\":\"structInternal.TimestampedPackedUint224[]\",\"name\":\"\",\"type\":\"tuple[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getTokenTransferFeeConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"minFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"maxFeeUSDCents\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"deciBps\",\"type\":\"uint16\"},{\"internalType\":\"uint32\",\"name\":\"destGasOverhead\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"destBytesOverhead\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"}],\"internalType\":\"structFeeQuoter.TokenTransferFeeConfig\",\"name\":\"tokenTransferFeeConfig\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"receiver\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"}],\"internalType\":\"structClient.EVM2AnyMessage\",\"name\":\"message\",\"type\":\"tuple\"}],\"name\":\"getValidatedFee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getValidatedTokenPrice\",\"outputs\":[{\"internalType\":\"uint224\",\"name\":\"\",\"type\":\"uint224\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"metadata\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"}],\"name\":\"onReport\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"feeToken\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"feeTokenAmount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"extraArgs\",\"type\":\"bytes\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"sourcePoolAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"destExecData\",\"type\":\"bytes\"}],\"internalType\":\"structInternal.EVM2AnyTokenTransfer[]\",\"name\":\"onRampTokenTransfers\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMTokenAmount[]\",\"name\":\"sourceTokenAmounts\",\"type\":\"tuple[]\"}],\"name\":\"processMessageArgs\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"msgFeeJuels\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"isOutOfOrderExecution\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"convertedExtraArgs\",\"type\":\"bytes\"},{\"internalType\":\"bytes[]\",\"name\":\"destExecDataPerToken\",\"type\":\"bytes[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"forwarder\",\"type\":\"address\"},{\"internalType\":\"bytes10\",\"name\":\"workflowName\",\"type\":\"bytes10\"},{\"internalType\":\"bytes2\",\"name\":\"reportName\",\"type\":\"bytes2\"},{\"internalType\":\"address\",\"name\":\"workflowOwner\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"isAllowed\",\"type\":\"bool\"}],\"internalType\":\"structKeystoneFeedsPermissionHandler.Permission[]\",\"name\":\"permissions\",\"type\":\"tuple[]\"}],\"name\":\"setReportPermissions\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"internalType\":\"uint224\",\"name\":\"usdPerToken\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.TokenPriceUpdate[]\",\"name\":\"tokenPriceUpdates\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint224\",\"name\":\"usdPerUnitGas\",\"type\":\"uint224\"}],\"internalType\":\"structInternal.GasPriceUpdate[]\",\"name\":\"gasPriceUpdates\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.PriceUpdates\",\"name\":\"priceUpdates\",\"type\":\"tuple\"}],\"name\":\"updatePrices\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"sourceToken\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"dataFeedAddress\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"tokenDecimals\",\"type\":\"uint8\"},{\"internalType\":\"bool\",\"name\":\"isEnabled\",\"type\":\"bool\"}],\"internalType\":\"structFeeQuoter.TokenPriceFeedConfig\",\"name\":\"feedConfig\",\"type\":\"tuple\"}],\"internalType\":\"structFeeQuoter.TokenPriceFeedUpdate[]\",\"name\":\"tokenPriceFeedUpdates\",\"type\":\"tuple[]\"}],\"name\":\"updateTokenPriceFeeds\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60e06040523480156200001157600080fd5b5060405162007a6838038062007a6883398101604081905262000034916200189c565b85336000816200005757604051639b15e16f60e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b03848116919091179091558116156200008a576200008a81620001d0565b5050604080518082018252828152815160008152602080820190935291810191909152620000b8906200024a565b5060208701516001600160a01b03161580620000dc575086516001600160601b0316155b80620000f05750604087015163ffffffff16155b156200010f5760405163d794ef9560e01b815260040160405180910390fd5b6020878101516001600160a01b031660a05287516001600160601b031660805260408089015163ffffffff1660c052805160008152918201905262000155908662000399565b6200016084620004e1565b6200016b81620005d9565b620001768262000a45565b60408051600080825260208201909252620001c391859190620001bc565b6040805180820190915260008082526020820152815260200190600190039081620001945790505b5062000b11565b5050505050505062001b5a565b336001600160a01b03821603620001fa57604051636d6c4ee560e11b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b03838116918217835560015460405192939116917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b602081015160005b8151811015620002da576000828281518110620002735762000273620019bb565b602090810291909101015190506200028d60028262000e97565b15620002d0576040516001600160a01b03821681527fc3803387881faad271c47728894e3e36fac830ffc8602ca6fc07733cbda775809060200160405180910390a15b5060010162000252565b50815160005b815181101562000393576000828281518110620003015762000301620019bb565b6020026020010151905060006001600160a01b0316816001600160a01b0316036200033f576040516342bcdf7f60e11b815260040160405180910390fd5b6200034c60028262000eb7565b506040516001600160a01b03821681527feb1b9b92e50b7f88f9ff25d56765095ac6e91540eee214906f4036a908ffbdef9060200160405180910390a150600101620002e0565b50505050565b60005b82518110156200043a57620003d8838281518110620003bf57620003bf620019bb565b6020026020010151600b62000ece60201b90919060201c565b156200043157828181518110620003f357620003f3620019bb565b60200260200101516001600160a01b03167f1795838dc8ab2ffc5f431a1729a6afa0b587f982f7b2be0b9d7187a1ef547f9160405160405180910390a25b6001016200039c565b5060005b8151811015620004dc576200047a828281518110620004615762000461620019bb565b6020026020010151600b62000eb760201b90919060201c565b15620004d357818181518110620004955762000495620019bb565b60200260200101516001600160a01b03167fdf1b1bd32a69711488d71554706bb130b1fc63a5fa1a2cd85e8440f84065ba2360405160405180910390a25b6001016200043e565b505050565b60005b8151811015620005d5576000828281518110620005055762000505620019bb565b6020908102919091018101518051818301516001600160a01b0380831660008181526007875260409081902084518154868a0180518589018051949098166001600160a81b03199093168317600160a01b60ff928316021760ff60a81b1916600160a81b9415159490940293909317909355835190815291511697810197909752915115159186019190915292945090929091907fe6a7a17d710bf0b2cd05e5397dc6f97a5da4ee79e31e234bf5f965ee2bd9a5bf9060600160405180910390a2505050806001019050620004e4565b5050565b60005b8151811015620005d5576000828281518110620005fd57620005fd620019bb565b6020026020010151905060008383815181106200061e576200061e620019bb565b6020026020010151600001519050600082602001519050816001600160401b03166000148062000657575061016081015163ffffffff16155b806200067957506102008101516001600160e01b031916630a04b54b60e21b14155b80620006995750806060015163ffffffff1681610160015163ffffffff16115b15620006c85760405163c35aa79d60e01b81526001600160401b03831660048201526024015b60405180910390fd5b6001600160401b038216600090815260096020526040812060010154600160a81b900460e01b6001600160e01b03191690036200074857816001600160401b03167f525e3d4e0c31cef19cf9426af8d2c0ddd2d576359ca26bed92aac5fadda46265826040516200073a9190620019d1565b60405180910390a26200078c565b816001600160401b03167f283b699f411baff8f1c29fe49f32a828c8151596244b8e7e4c164edd6569a83582604051620007839190620019d1565b60405180910390a25b8060096000846001600160401b03166001600160401b0316815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548161ffff021916908361ffff16021790555060408201518160000160036101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160076101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600b6101000a81548163ffffffff021916908363ffffffff16021790555060a082015181600001600f6101000a81548161ffff021916908361ffff16021790555060c08201518160000160116101000a81548163ffffffff021916908363ffffffff16021790555060e08201518160000160156101000a81548161ffff021916908361ffff1602179055506101008201518160000160176101000a81548161ffff021916908361ffff1602179055506101208201518160000160196101000a81548161ffff021916908361ffff16021790555061014082015181600001601b6101000a81548163ffffffff021916908363ffffffff1602179055506101608201518160010160006101000a81548163ffffffff021916908363ffffffff1602179055506101808201518160010160046101000a8154816001600160401b0302191690836001600160401b031602179055506101a082015181600101600c6101000a81548163ffffffff021916908363ffffffff1602179055506101c08201518160010160106101000a81548163ffffffff021916908363ffffffff1602179055506101e08201518160010160146101000a81548160ff0219169083151502179055506102008201518160010160156101000a81548163ffffffff021916908360e01c0217905550905050505050806001019050620005dc565b60005b8151811015620005d557600082828151811062000a695762000a69620019bb565b6020026020010151600001519050600083838151811062000a8e5762000a8e620019bb565b6020908102919091018101518101516001600160a01b03841660008181526008845260409081902080546001600160401b0319166001600160401b0385169081179091559051908152919350917fbb77da6f7210cdd16904228a9360133d1d7dfff99b1bc75f128da5b53e28f97d910160405180910390a2505060010162000a48565b60005b825181101562000dd157600083828151811062000b355762000b35620019bb565b6020026020010151905060008160000151905060005b82602001515181101562000dc25760008360200151828151811062000b745762000b74620019bb565b602002602001015160200151905060008460200151838151811062000b9d5762000b9d620019bb565b6020026020010151600001519050816020015163ffffffff16826000015163ffffffff161062000bf857815160208301516040516305a7b3d160e11b815263ffffffff928316600482015291166024820152604401620006bf565b602063ffffffff16826080015163ffffffff16101562000c495760808201516040516312766e0160e11b81526001600160a01b038316600482015263ffffffff9091166024820152604401620006bf565b6001600160401b0384166000818152600a602090815260408083206001600160a01b0386168085529083529281902086518154938801518389015160608a015160808b015160a08c01511515600160901b0260ff60901b1963ffffffff928316600160701b021664ffffffffff60701b199383166a01000000000000000000000263ffffffff60501b1961ffff90961668010000000000000000029590951665ffffffffffff60401b19968416640100000000026001600160401b0319909b16939097169290921798909817939093169390931717919091161792909217909155519091907f94967ae9ea7729ad4f54021c1981765d2b1d954f7c92fbec340aa0a54f46b8b59062000daf908690600060c08201905063ffffffff80845116835280602085015116602084015261ffff60408501511660408401528060608501511660608401528060808501511660808401525060a0830151151560a083015292915050565b60405180910390a3505060010162000b4b565b50505080600101905062000b14565b5060005b8151811015620004dc57600082828151811062000df65762000df6620019bb565b6020026020010151600001519050600083838151811062000e1b5762000e1b620019bb565b6020908102919091018101518101516001600160401b0384166000818152600a845260408082206001600160a01b038516808452955280822080546001600160981b03191690555192945090917f4de5b1bcbca6018c11303a2c3f4a4b4f22a1c741d8c4ba430d246ac06c5ddf8b9190a3505060010162000dd5565b600062000eae836001600160a01b03841662000ee5565b90505b92915050565b600062000eae836001600160a01b03841662000fe9565b600062000eae836001600160a01b0384166200103b565b6000818152600183016020526040812054801562000fde57600062000f0c60018362001b22565b855490915060009062000f229060019062001b22565b905081811462000f8e57600086600001828154811062000f465762000f46620019bb565b906000526020600020015490508087600001848154811062000f6c5762000f6c620019bb565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062000fa25762000fa262001b44565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062000eb1565b600091505062000eb1565b6000818152600183016020526040812054620010325750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000eb1565b50600062000eb1565b6000818152600183016020526040812054801562000fde5760006200106260018362001b22565b8554909150600090620010789060019062001b22565b905080821462000f8e57600086600001828154811062000f465762000f46620019bb565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715620010d757620010d76200109c565b60405290565b604080519081016001600160401b0381118282101715620010d757620010d76200109c565b60405160c081016001600160401b0381118282101715620010d757620010d76200109c565b60405161022081016001600160401b0381118282101715620010d757620010d76200109c565b604051601f8201601f191681016001600160401b03811182821017156200117857620011786200109c565b604052919050565b80516001600160a01b03811681146200119857600080fd5b919050565b805163ffffffff811681146200119857600080fd5b600060608284031215620011c557600080fd5b620011cf620010b2565b82519091506001600160601b0381168114620011ea57600080fd5b8152620011fa6020830162001180565b60208201526200120d604083016200119d565b604082015292915050565b60006001600160401b038211156200123457620012346200109c565b5060051b60200190565b600082601f8301126200125057600080fd5b8151602062001269620012638362001218565b6200114d565b8083825260208201915060208460051b8701019350868411156200128c57600080fd5b602086015b84811015620012b357620012a58162001180565b835291830191830162001291565b509695505050505050565b805180151581146200119857600080fd5b600082601f830112620012e157600080fd5b81516020620012f4620012638362001218565b82815260079290921b840181019181810190868411156200131457600080fd5b8286015b84811015620012b3578088036080811215620013345760008081fd5b6200133e620010dd565b620013498362001180565b8152606080601f1984011215620013605760008081fd5b6200136a620010b2565b92506200137987850162001180565b835260408085015160ff81168114620013925760008081fd5b84890152620013a3858301620012be565b90840152508086019190915283529183019160800162001318565b80516001600160401b03811681146200119857600080fd5b805161ffff811681146200119857600080fd5b600082601f830112620013fb57600080fd5b815160206200140e620012638362001218565b82815260059290921b840181019181810190868411156200142e57600080fd5b8286015b84811015620012b35780516001600160401b03808211156200145357600080fd5b908801906040601f19838c0381018213156200146e57600080fd5b62001478620010dd565b62001485898601620013be565b815282850151848111156200149957600080fd5b8086019550508c603f860112620014af57600080fd5b888501519350620014c4620012638562001218565b84815260e09094028501830193898101908e861115620014e357600080fd5b958401955b85871015620015bc57868f0360e08112156200150357600080fd5b6200150d620010dd565b620015188962001180565b815260c086830112156200152b57600080fd5b6200153562001102565b9150620015448d8a016200119d565b825262001553878a016200119d565b8d8301526200156560608a01620013d6565b878301526200157760808a016200119d565b60608301526200158a60a08a016200119d565b60808301526200159d60c08a01620012be565b60a0830152808d0191909152825260e09690960195908a0190620014e8565b828b01525087525050509284019250830162001432565b600082601f830112620015e557600080fd5b81516020620015f8620012638362001218565b82815260069290921b840181019181810190868411156200161857600080fd5b8286015b84811015620012b35760408189031215620016375760008081fd5b62001641620010dd565b6200164c8262001180565b81526200165b858301620013be565b818601528352918301916040016200161c565b80516001600160e01b0319811681146200119857600080fd5b600082601f8301126200169957600080fd5b81516020620016ac620012638362001218565b8281526102409283028501820192828201919087851115620016cd57600080fd5b8387015b858110156200188f5780890382811215620016ec5760008081fd5b620016f6620010dd565b6200170183620013be565b815261022080601f1984011215620017195760008081fd5b6200172362001127565b925062001732888501620012be565b8352604062001743818601620013d6565b898501526060620017568187016200119d565b82860152608091506200176b8287016200119d565b9085015260a06200177e8682016200119d565b8286015260c0915062001793828701620013d6565b9085015260e0620017a68682016200119d565b828601526101009150620017bc828701620013d6565b90850152610120620017d0868201620013d6565b828601526101409150620017e6828701620013d6565b90850152610160620017fa8682016200119d565b828601526101809150620018108287016200119d565b908501526101a062001824868201620013be565b828601526101c091506200183a8287016200119d565b908501526101e06200184e8682016200119d565b82860152610200915062001864828701620012be565b90850152620018758583016200166e565b9084015250808701919091528452928401928101620016d1565b5090979650505050505050565b6000806000806000806000610120888a031215620018b957600080fd5b620018c58989620011b2565b60608901519097506001600160401b0380821115620018e357600080fd5b620018f18b838c016200123e565b975060808a01519150808211156200190857600080fd5b620019168b838c016200123e565b965060a08a01519150808211156200192d57600080fd5b6200193b8b838c01620012cf565b955060c08a01519150808211156200195257600080fd5b620019608b838c01620013e9565b945060e08a01519150808211156200197757600080fd5b620019858b838c01620015d3565b93506101008a01519150808211156200199d57600080fd5b50620019ac8a828b0162001687565b91505092959891949750929550565b634e487b7160e01b600052603260045260246000fd5b81511515815261022081016020830151620019f2602084018261ffff169052565b50604083015162001a0b604084018263ffffffff169052565b50606083015162001a24606084018263ffffffff169052565b50608083015162001a3d608084018263ffffffff169052565b5060a083015162001a5460a084018261ffff169052565b5060c083015162001a6d60c084018263ffffffff169052565b5060e083015162001a8460e084018261ffff169052565b506101008381015161ffff9081169184019190915261012080850151909116908301526101408084015163ffffffff9081169184019190915261016080850151821690840152610180808501516001600160401b0316908401526101a0808501518216908401526101c080850151909116908301526101e080840151151590830152610200928301516001600160e01b031916929091019190915290565b8181038181111562000eb157634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60805160a05160c051615ebb62001bad6000396000818161032801526119170152600081816102ec0152818161103401526110940152600081816102b8015281816110bd015261112d0152615ebb6000f3fe608060405234801561001057600080fd5b50600436106101e45760003560e01c8063770e2dc41161010f578063bf78e03f116100a2578063d8694ccd11610071578063d8694ccd14610b04578063f2fde38b14610b17578063fbe3f77814610b2a578063ffdb4b3714610b3d57600080fd5b8063bf78e03f14610a03578063cdc73d5114610ae1578063d02641a014610ae9578063d63d3af214610afc57600080fd5b806382b49eb0116100de57806382b49eb0146108455780638da5cb5b146109b557806391a2749a146109dd578063a69c64c0146109f057600080fd5b8063770e2dc41461080457806379ba5097146108175780637afac3221461081f578063805f21321461083257600080fd5b80633937306f116101875780634ab35b0b116101565780634ab35b0b14610472578063514e8cff146104b25780636cb5f3dd146105555780636def4ce71461056857600080fd5b80633937306f1461040757806341ed29e71461041c578063430d138c1461042f57806345ac924d1461045257600080fd5b806306285c69116101c357806306285c691461028b578063181f5a77146103a15780632451a627146103ea578063325c868e146103ff57600080fd5b806241e5be146101e957806301ffc9a71461020f578063061877e314610232575b600080fd5b6101fc6101f7366004614568565b610b85565b6040519081526020015b60405180910390f35b61022261021d3660046145d4565b610bf3565b6040519015158152602001610206565b6102726102403660046145ef565b73ffffffffffffffffffffffffffffffffffffffff1660009081526008602052604090205467ffffffffffffffff1690565b60405167ffffffffffffffff9091168152602001610206565b610355604080516060810182526000808252602082018190529181019190915260405180606001604052807f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000063ffffffff16815250905090565b6040805182516bffffffffffffffffffffffff16815260208084015173ffffffffffffffffffffffffffffffffffffffff16908201529181015163ffffffff1690820152606001610206565b6103dd6040518060400160405280601381526020017f46656551756f74657220312e362e302d6465760000000000000000000000000081525081565b604051610206919061466e565b6103f2610d24565b6040516102069190614681565b6101fc602481565b61041a6104153660046146db565b610d35565b005b61041a61042a366004614887565b610fea565b61044261043d366004614a72565b61102c565b6040516102069493929190614b66565b610465610460366004614c05565b61123c565b6040516102069190614c47565b6104856104803660046145ef565b611305565b6040517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff9091168152602001610206565b6105486104c0366004614cc2565b60408051808201909152600080825260208201525067ffffffffffffffff166000908152600560209081526040918290208251808401909352547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811683527c0100000000000000000000000000000000000000000000000000000000900463ffffffff169082015290565b6040516102069190614cdd565b61041a610563366004614d3e565b611310565b6107f7610576366004614cc2565b6040805161022081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081018290526101e081018290526102008101919091525067ffffffffffffffff908116600090815260096020908152604091829020825161022081018452815460ff8082161515835261ffff61010080840482169685019690965263ffffffff630100000084048116978501979097526701000000000000008304871660608501526b0100000000000000000000008304871660808501526f010000000000000000000000000000008304811660a0850152710100000000000000000000000000000000008304871660c08501527501000000000000000000000000000000000000000000808404821660e08087019190915277010000000000000000000000000000000000000000000000850483169786019790975279010000000000000000000000000000000000000000000000000084049091166101208501527b01000000000000000000000000000000000000000000000000000000909204861661014084015260019093015480861661016084015264010000000081049096166101808301526c01000000000000000000000000860485166101a083015270010000000000000000000000000000000086049094166101c082015274010000000000000000000000000000000000000000850490911615156101e08201527fffffffff0000000000000000000000000000000000000000000000000000000092909304901b1661020082015290565b6040516102069190614f5e565b61041a61081236600461515c565b611324565b61041a611336565b61041a61082d366004615476565b611404565b61041a6108403660046154da565b611416565b610955610853366004615546565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091525067ffffffffffffffff919091166000908152600a6020908152604080832073ffffffffffffffffffffffffffffffffffffffff94909416835292815290829020825160c081018452905463ffffffff8082168352640100000000820481169383019390935268010000000000000000810461ffff16938201939093526a01000000000000000000008304821660608201526e01000000000000000000000000000083049091166080820152720100000000000000000000000000000000000090910460ff16151560a082015290565b6040516102069190600060c08201905063ffffffff80845116835280602085015116602084015261ffff60408501511660408401528060608501511660608401528060808501511660808401525060a0830151151560a083015292915050565b60015460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610206565b61041a6109eb366004615570565b611852565b61041a6109fe366004615601565b611863565b610aa4610a113660046145ef565b60408051606080820183526000808352602080840182905292840181905273ffffffffffffffffffffffffffffffffffffffff9485168152600783528390208351918201845254938416815260ff74010000000000000000000000000000000000000000850481169282019290925275010000000000000000000000000000000000000000009093041615159082015290565b60408051825173ffffffffffffffffffffffffffffffffffffffff16815260208084015160ff169082015291810151151590820152606001610206565b6103f2611874565b610548610af73660046145ef565b611880565b6101fc601281565b6101fc610b123660046156c6565b611a35565b61041a610b253660046145ef565b611f6d565b61041a610b3836600461572a565b611f7e565b610b50610b4b36600461584a565b611f8f565b604080517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201610206565b6000610b9082612047565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16610bb785612047565b610bdf907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16856158a3565b610be991906158ba565b90505b9392505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f805f2132000000000000000000000000000000000000000000000000000000001480610c8657507fffffffff0000000000000000000000000000000000000000000000000000000082167f9b645f4100000000000000000000000000000000000000000000000000000000145b80610cd257507fffffffff0000000000000000000000000000000000000000000000000000000082167f181f5a7700000000000000000000000000000000000000000000000000000000145b80610d1e57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b6060610d3060026120e1565b905090565b610d3d6120ee565b6000610d4982806158f5565b9050905060005b81811015610e93576000610d6484806158f5565b83818110610d7457610d7461595d565b905060400201803603810190610d8a91906159b8565b604080518082018252602080840180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff908116845263ffffffff42818116858701908152885173ffffffffffffffffffffffffffffffffffffffff9081166000908152600690975295889020965190519092167c010000000000000000000000000000000000000000000000000000000002919092161790935584519051935194955016927f52f50aa6d1a95a4595361ecf953d095f125d442e4673716dede699e049de148a92610e829290917bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b60405180910390a250600101610d50565b506000610ea360208401846158f5565b9050905060005b81811015610fe4576000610ec160208601866158f5565b83818110610ed157610ed161595d565b905060400201803603810190610ee791906159f5565b604080518082018252602080840180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff908116845263ffffffff42818116858701908152885167ffffffffffffffff9081166000908152600590975295889020965190519092167c010000000000000000000000000000000000000000000000000000000002919092161790935584519051935194955016927fdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e92610fd39290917bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b60405180910390a250600101610eaa565b50505050565b610ff2612133565b60005b8151811015611028576110208282815181106110135761101361595d565b6020026020010151612184565b600101610ff5565b5050565b6000806060807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168c73ffffffffffffffffffffffffffffffffffffffff160361108d578a93506110bb565b6110b88c8c7f0000000000000000000000000000000000000000000000000000000000000000610b85565b93505b7f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff1684111561115f576040517f6a92a483000000000000000000000000000000000000000000000000000000008152600481018590526bffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b67ffffffffffffffff8d1660009081526009602052604081206001015463ffffffff169061118e8c8c84612356565b9050806020015194506111a48f8b8b8b8b6124ff565b92508585611224836040805182516024820152602092830151151560448083019190915282518083039091018152606490910190915290810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f181dcf100000000000000000000000000000000000000000000000000000000017905290565b95509550955050509950995099509995505050505050565b60608160008167ffffffffffffffff81111561125a5761125a614716565b60405190808252806020026020018201604052801561129f57816020015b60408051808201909152600080825260208201528152602001906001900390816112785790505b50905060005b828110156112fc576112d78686838181106112c2576112c261595d565b9050602002016020810190610af791906145ef565b8282815181106112e9576112e961595d565b60209081029190910101526001016112a5565b50949350505050565b6000610d1e82612047565b611318612133565b61132181612882565b50565b61132c612133565b6110288282612d54565b60005473ffffffffffffffffffffffffffffffffffffffff163314611387576040517f02b543c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560008054909116815560405173ffffffffffffffffffffffffffffffffffffffff909216929183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61140c612133565b61102882826131ca565b600080600061145a87878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061331192505050565b92509250925061146c3383858461332c565b600061147a85870187615a18565b905060005b8151811015611847576000600760008484815181106114a0576114a061595d565b6020908102919091018101515173ffffffffffffffffffffffffffffffffffffffff908116835282820193909352604091820160002082516060810184529054938416815260ff740100000000000000000000000000000000000000008504811692820192909252750100000000000000000000000000000000000000000090930416151590820181905290915061159b578282815181106115445761154461595d565b6020908102919091010151516040517f06439c6b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401611156565b60006115e8601283602001518686815181106115b9576115b961595d565b6020026020010151602001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16613484565b9050600660008585815181106116005761160061595d565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001601c9054906101000a900463ffffffff1663ffffffff168484815181106116725761167261595d565b60200260200101516040015163ffffffff16101561169157505061183f565b6040518060400160405280827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1681526020018585815181106116d2576116d261595d565b60200260200101516040015163ffffffff16815250600660008686815181106116fd576116fd61595d565b6020908102919091018101515173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251929091015163ffffffff167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117905583518490849081106117955761179561595d565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff167f52f50aa6d1a95a4595361ecf953d095f125d442e4673716dede699e049de148a828686815181106117eb576117eb61595d565b6020026020010151604001516040516118349291907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff92909216825263ffffffff16602082015260400190565b60405180910390a250505b60010161147f565b505050505050505050565b61185a612133565b61132181613547565b61186b612133565b611321816136d3565b6060610d30600b6120e1565b604080518082019091526000808252602082015273ffffffffffffffffffffffffffffffffffffffff82166000908152600660209081526040918290208251808401909352547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116835263ffffffff7c010000000000000000000000000000000000000000000000000000000090910481169183018290527f000000000000000000000000000000000000000000000000000000000000000016906119429042615adf565b101561194e5792915050565b73ffffffffffffffffffffffffffffffffffffffff80841660009081526007602090815260409182902082516060810184529054938416815260ff74010000000000000000000000000000000000000000850481169282019290925275010000000000000000000000000000000000000000009093041615801591830191909152806119ef5750805173ffffffffffffffffffffffffffffffffffffffff16155b156119fb575092915050565b6000611a06826137bd565b9050826020015163ffffffff16816020015163ffffffff161015611a2a5782611a2c565b805b95945050505050565b67ffffffffffffffff8083166000908152600960209081526040808320815161022081018352815460ff808216151580845261ffff61010080850482169886019890985263ffffffff630100000085048116978601979097526701000000000000008404871660608601526b0100000000000000000000008404871660808601526f010000000000000000000000000000008404811660a0860152710100000000000000000000000000000000008404871660c08601527501000000000000000000000000000000000000000000808504821660e08088019190915277010000000000000000000000000000000000000000000000860483169987019990995279010000000000000000000000000000000000000000000000000085049091166101208601527b01000000000000000000000000000000000000000000000000000000909304861661014085015260019094015480861661016085015264010000000081049098166101808401526c01000000000000000000000000880485166101a084015270010000000000000000000000000000000088049094166101c083015274010000000000000000000000000000000000000000870490931615156101e08201527fffffffff000000000000000000000000000000000000000000000000000000009290950490921b16610200840152909190611c6f576040517f99ac52f200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff85166004820152602401611156565b611c8a611c8260808501606086016145ef565b600b9061394f565b611ce957611c9e60808401606085016145ef565b6040517f2502348c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401611156565b6000611cf860408501856158f5565b9150611d54905082611d0d6020870187615af2565b905083611d1a8880615af2565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061397e92505050565b6000611d6e611d6960808701606088016145ef565b612047565b90506000611d8187856101c00151613a3b565b9050600080808515611dc157611db5878b611da260808d0160608e016145ef565b88611db060408f018f6158f5565b613b3b565b91945092509050611de1565b6101a0870151611dde9063ffffffff16662386f26fc100006158a3565b92505b61010087015160009061ffff1615611e2557611e22886dffffffffffffffffffffffffffff607088901c16611e1960208e018e615af2565b90508a86613e13565b90505b61018088015160009067ffffffffffffffff16611e4e611e4860808e018e615af2565b8c613ec3565b600001518563ffffffff168b60a0015161ffff168e8060200190611e729190615af2565b611e7d9291506158a3565b8c6080015163ffffffff16611e929190615b57565b611e9c9190615b57565b611ea69190615b57565b611ec0906dffffffffffffffffffffffffffff89166158a3565b611eca91906158a3565b9050867bffffffffffffffffffffffffffffffffffffffffffffffffffffffff168282600860008f6060016020810190611f0491906145ef565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002054611f3f9067ffffffffffffffff16896158a3565b611f499190615b57565b611f539190615b57565b611f5d91906158ba565b9c9b505050505050505050505050565b611f75612133565b61132181613f84565b611f86612133565b61132181614048565b67ffffffffffffffff8116600090815260096020526040812054819060ff16611ff0576040517f99ac52f200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152602401611156565b611ff984612047565b67ffffffffffffffff841660009081526009602052604090206001015461203b908590700100000000000000000000000000000000900463ffffffff16613a3b565b915091505b9250929050565b60008061205383611880565b9050806020015163ffffffff166000148061208b575080517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16155b156120da576040517f06439c6b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401611156565b5192915050565b60606000610bec8361419a565b6120f960023361394f565b612131576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401611156565b565b60015473ffffffffffffffffffffffffffffffffffffffff163314612131576040517f2b5c74de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061223d82600001518360600151846020015185604001516040805173ffffffffffffffffffffffffffffffffffffffff80871660208301528516918101919091527fffffffffffffffffffff00000000000000000000000000000000000000000000831660608201527fffff0000000000000000000000000000000000000000000000000000000000008216608082015260009060a001604051602081830303815290604052805190602001209050949350505050565b60808301516000828152600460205260409081902080549215157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00909316929092179091555190915081907f32a4ba3fa3351b11ad555d4c8ec70a744e8705607077a946807030d64b6ab1a39061234a908590600060a08201905073ffffffffffffffffffffffffffffffffffffffff8084511683527fffffffffffffffffffff0000000000000000000000000000000000000000000060208501511660208401527fffff00000000000000000000000000000000000000000000000000000000000060408501511660408401528060608501511660608401525060808301511515608083015292915050565b60405180910390a25050565b6040805180820190915260008082526020820152600083900361239757506040805180820190915267ffffffffffffffff8216815260006020820152610bec565b60006123a38486615b6a565b905060006123b48560048189615bb0565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293505050507fffffffff0000000000000000000000000000000000000000000000000000000082167fe7e230f0000000000000000000000000000000000000000000000000000000000161245157808060200190518101906124489190615bda565b92505050610bec565b7f6859a837000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316016124cd576040518060400160405280828060200190518101906124b99190615c06565b815260006020909101529250610bec915050565b6040517f5247fdce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff808616600090815260096020526040902060010154606091750100000000000000000000000000000000000000000090910460e01b90859081111561254f5761254f614716565b60405190808252806020026020018201604052801561258257816020015b606081526020019060019003908161256d5790505b50915060005b858110156128775760008585838181106125a4576125a461595d565b6125ba92602060409092020190810191506145ef565b905060008888848181106125d0576125d061595d565b90506020028101906125e29190615c1f565b6125f0906040810190615af2565b91505060208111156126a05767ffffffffffffffff8a166000908152600a6020908152604080832073ffffffffffffffffffffffffffffffffffffffff861684529091529020546e010000000000000000000000000000900463ffffffff168111156126a0576040517f36f536ca00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401611156565b612710848a8a868181106126b6576126b661595d565b90506020028101906126c89190615c1f565b6126d6906020810190615af2565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506141f692505050565b67ffffffffffffffff8a166000908152600a6020908152604080832073ffffffffffffffffffffffffffffffffffffffff861684528252808320815160c081018352905463ffffffff8082168352640100000000820481169483019490945268010000000000000000810461ffff16928201929092526a01000000000000000000008204831660608201526e010000000000000000000000000000820490921660808301527201000000000000000000000000000000000000900460ff16151560a082018190529091906128225767ffffffffffffffff8c166000908152600960205260409020547b01000000000000000000000000000000000000000000000000000000900463ffffffff16612828565b81606001515b6040805163ffffffff831660208201529192500160405160208183030381529060405287868151811061285d5761285d61595d565b602002602001018190525050505050806001019050612588565b505095945050505050565b60005b81518110156110285760008282815181106128a2576128a261595d565b6020026020010151905060008383815181106128c0576128c061595d565b60200260200101516000015190506000826020015190508167ffffffffffffffff16600014806128f9575061016081015163ffffffff16155b8061294b57506102008101517fffffffff00000000000000000000000000000000000000000000000000000000167f2812d52c0000000000000000000000000000000000000000000000000000000014155b8061296a5750806060015163ffffffff1681610160015163ffffffff16115b156129ad576040517fc35aa79d00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff83166004820152602401611156565b67ffffffffffffffff82166000908152600960205260408120600101547501000000000000000000000000000000000000000000900460e01b7fffffffff00000000000000000000000000000000000000000000000000000000169003612a55578167ffffffffffffffff167f525e3d4e0c31cef19cf9426af8d2c0ddd2d576359ca26bed92aac5fadda4626582604051612a489190614f5e565b60405180910390a2612a98565b8167ffffffffffffffff167f283b699f411baff8f1c29fe49f32a828c8151596244b8e7e4c164edd6569a83582604051612a8f9190614f5e565b60405180910390a25b80600960008467ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548161ffff021916908361ffff16021790555060408201518160000160036101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160076101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600b6101000a81548163ffffffff021916908363ffffffff16021790555060a082015181600001600f6101000a81548161ffff021916908361ffff16021790555060c08201518160000160116101000a81548163ffffffff021916908363ffffffff16021790555060e08201518160000160156101000a81548161ffff021916908361ffff1602179055506101008201518160000160176101000a81548161ffff021916908361ffff1602179055506101208201518160000160196101000a81548161ffff021916908361ffff16021790555061014082015181600001601b6101000a81548163ffffffff021916908363ffffffff1602179055506101608201518160010160006101000a81548163ffffffff021916908363ffffffff1602179055506101808201518160010160046101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506101a082015181600101600c6101000a81548163ffffffff021916908363ffffffff1602179055506101c08201518160010160106101000a81548163ffffffff021916908363ffffffff1602179055506101e08201518160010160146101000a81548160ff0219169083151502179055506102008201518160010160156101000a81548163ffffffff021916908360e01c0217905550905050505050806001019050612885565b60005b82518110156130e1576000838281518110612d7457612d7461595d565b6020026020010151905060008160000151905060005b8260200151518110156130d357600083602001518281518110612daf57612daf61595d565b6020026020010151602001519050600084602001518381518110612dd557612dd561595d565b6020026020010151600001519050816020015163ffffffff16826000015163ffffffff1610612e4757815160208301516040517f0b4f67a200000000000000000000000000000000000000000000000000000000815263ffffffff928316600482015291166024820152604401611156565b602063ffffffff16826080015163ffffffff161015612ebc5760808201516040517f24ecdc0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316600482015263ffffffff9091166024820152604401611156565b67ffffffffffffffff84166000818152600a6020908152604080832073ffffffffffffffffffffffffffffffffffffffff86168085529083529281902086518154938801518389015160608a015160808b015160a08c015115157201000000000000000000000000000000000000027fffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff63ffffffff9283166e01000000000000000000000000000002167fffffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffff9383166a0100000000000000000000027fffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffff61ffff9096166801000000000000000002959095167fffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffff968416640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b16939097169290921798909817939093169390931717919091161792909217909155519091907f94967ae9ea7729ad4f54021c1981765d2b1d954f7c92fbec340aa0a54f46b8b5906130c1908690600060c08201905063ffffffff80845116835280602085015116602084015261ffff60408501511660408401528060608501511660608401528060808501511660808401525060a0830151151560a083015292915050565b60405180910390a35050600101612d8a565b505050806001019050612d57565b5060005b81518110156131c55760008282815181106131025761310261595d565b602002602001015160000151905060008383815181106131245761312461595d565b60209081029190910181015181015167ffffffffffffffff84166000818152600a8452604080822073ffffffffffffffffffffffffffffffffffffffff8516808452955280822080547fffffffffffffffffffffffffff000000000000000000000000000000000000001690555192945090917f4de5b1bcbca6018c11303a2c3f4a4b4f22a1c741d8c4ba430d246ac06c5ddf8b9190a350506001016130e5565b505050565b60005b825181101561326d576132038382815181106131eb576131eb61595d565b6020026020010151600b61424890919063ffffffff16565b156132655782818151811061321a5761321a61595d565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167f1795838dc8ab2ffc5f431a1729a6afa0b587f982f7b2be0b9d7187a1ef547f9160405160405180910390a25b6001016131cd565b5060005b81518110156131c5576132a782828151811061328f5761328f61595d565b6020026020010151600b61426a90919063ffffffff16565b15613309578181815181106132be576132be61595d565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167fdf1b1bd32a69711488d71554706bb130b1fc63a5fa1a2cd85e8440f84065ba2360405160405180910390a25b600101613271565b6040810151604a820151605e90920151909260609290921c91565b6040805173ffffffffffffffffffffffffffffffffffffffff868116602080840191909152908616828401527fffffffffffffffffffff00000000000000000000000000000000000000000000851660608301527fffff00000000000000000000000000000000000000000000000000000000000084166080808401919091528351808403909101815260a09092018352815191810191909120600081815260049092529190205460ff1661347d576040517f097e17ff00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8087166004830152851660248201527fffffffffffffffffffff00000000000000000000000000000000000000000000841660448201527fffff00000000000000000000000000000000000000000000000000000000000083166064820152608401611156565b5050505050565b6000806134918486615c5d565b9050600060248260ff1611156134cb576134af602460ff8416615adf565b6134ba90600a615d96565b6134c490856158ba565b90506134f1565b6134d960ff83166024615adf565b6134e490600a615d96565b6134ee90856158a3565b90505b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811115611a2c576040517f10cb51d100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081015160005b81518110156135e257600082828151811061356c5761356c61595d565b6020026020010151905061358a81600261428c90919063ffffffff16565b156135d95760405173ffffffffffffffffffffffffffffffffffffffff821681527fc3803387881faad271c47728894e3e36fac830ffc8602ca6fc07733cbda775809060200160405180910390a15b5060010161354f565b50815160005b8151811015610fe45760008282815181106136055761360561595d565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603613675576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61368060028261426a565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527feb1b9b92e50b7f88f9ff25d56765095ac6e91540eee214906f4036a908ffbdef9060200160405180910390a1506001016135e8565b60005b81518110156110285760008282815181106136f3576136f361595d565b602002602001015160000151905060008383815181106137155761371561595d565b60209081029190910181015181015173ffffffffffffffffffffffffffffffffffffffff841660008181526008845260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff85169081179091559051908152919350917fbb77da6f7210cdd16904228a9360133d1d7dfff99b1bc75f128da5b53e28f97d910160405180910390a250506001016136d6565b60408051808201909152600080825260208201526000826000015190506000808273ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613828573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061384c9190615dbc565b50935050925050600082121561388e576040517f10cb51d100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061390d8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156138de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139029190615e0c565b876020015185613484565b604080518082019091527bffffffffffffffffffffffffffffffffffffffffffffffffffffffff909116815263ffffffff909216602083015250949350505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001830160205260408120541515610bec565b836040015163ffffffff168311156139d75760408085015190517f8693378900000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015260248101849052604401611156565b836020015161ffff16821115613a2c5760208401516040517fd88dddd60000000000000000000000000000000000000000000000000000000081526004810184905261ffff9091166024820152604401611156565b610fe4846102000151826141f6565b67ffffffffffffffff821660009081526005602090815260408083208151808301909252547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116825263ffffffff7c010000000000000000000000000000000000000000000000000000000090910481169282019290925290831615613b33576000816020015163ffffffff1642613ad09190615adf565b90508363ffffffff16811115613b31576040517ff08bcb3e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8616600482015263ffffffff8516602482015260448101829052606401611156565b505b519392505050565b6000808083815b81811015613e05576000878783818110613b5e57613b5e61595d565b905060400201803603810190613b749190615e29565b67ffffffffffffffff8c166000908152600a60209081526040808320845173ffffffffffffffffffffffffffffffffffffffff168452825291829020825160c081018452905463ffffffff8082168352640100000000820481169383019390935268010000000000000000810461ffff16938201939093526a01000000000000000000008304821660608201526e01000000000000000000000000000083049091166080820152720100000000000000000000000000000000000090910460ff16151560a0820181905291925090613c94576101208d0151613c619061ffff16662386f26fc100006158a3565b613c6b9088615b57565b96508c610140015186613c7e9190615e62565b9550613c8b602086615e62565b94505050613dfd565b604081015160009061ffff1615613d4d5760008c73ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff1614613cf0578351613ce990612047565b9050613cf3565b508a5b620186a0836040015161ffff16613d358660200151847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166142ae90919063ffffffff16565b613d3f91906158a3565b613d4991906158ba565b9150505b6060820151613d5c9088615e62565b9650816080015186613d6e9190615e62565b8251909650600090613d8d9063ffffffff16662386f26fc100006158a3565b905080821015613dac57613da1818a615b57565b985050505050613dfd565b6000836020015163ffffffff16662386f26fc10000613dcb91906158a3565b905080831115613deb57613ddf818b615b57565b99505050505050613dfd565b613df5838b615b57565b995050505050505b600101613b42565b505096509650969350505050565b60008063ffffffff8316613e29610120866158a3565b613e35876101e0615b57565b613e3f9190615b57565b613e499190615b57565b905060008760c0015163ffffffff168860e0015161ffff1683613e6c91906158a3565b613e769190615b57565b61010089015190915061ffff16613e9d6dffffffffffffffffffffffffffff8916836158a3565b613ea791906158a3565b613eb790655af3107a40006158a3565b98975050505050505050565b60408051808201909152600080825260208201526000613eef858585610160015163ffffffff16612356565b9050826060015163ffffffff1681600001511115613f39576040517f4c4fc93a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826101e001518015613f4d57508060200151155b15610be9576040517fee433e9900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff821603613fd3576040517fdad89dca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217835560015460405192939116917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005b81518110156110285760008282815181106140685761406861595d565b60209081029190910181015180518183015173ffffffffffffffffffffffffffffffffffffffff80831660008181526007875260409081902084518154868a0180518589018051949098167fffffffffffffffffffffff00000000000000000000000000000000000000000090931683177401000000000000000000000000000000000000000060ff92831602177fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1675010000000000000000000000000000000000000000009415159490940293909317909355835190815291511697810197909752915115159186019190915292945090929091907fe6a7a17d710bf0b2cd05e5397dc6f97a5da4ee79e31e234bf5f965ee2bd9a5bf9060600160405180910390a250505080600101905061404b565b6060816000018054806020026020016040519081016040528092919081815260200182805480156141ea57602002820191906000526020600020905b8154815260200190600101908083116141d6575b50505050509050919050565b7fd7ed2ad4000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831601611028576131c5816142eb565b6000610bec8373ffffffffffffffffffffffffffffffffffffffff841661439e565b6000610bec8373ffffffffffffffffffffffffffffffffffffffff8416614498565b6000610bec8373ffffffffffffffffffffffffffffffffffffffff84166144e7565b6000670de0b6b3a76400006142e1837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff86166158a3565b610bec91906158ba565b6000815160201461432a57816040517f8d666f60000000000000000000000000000000000000000000000000000000008152600401611156919061466e565b6000828060200190518101906143409190615c06565b905073ffffffffffffffffffffffffffffffffffffffff811180614365575061040081105b15610d1e57826040517f8d666f60000000000000000000000000000000000000000000000000000000008152600401611156919061466e565b600081815260018301602052604081205480156144875760006143c2600183615adf565b85549091506000906143d690600190615adf565b905080821461443b5760008660000182815481106143f6576143f661595d565b90600052602060002001549050808760000184815481106144195761441961595d565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061444c5761444c615e7f565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610d1e565b6000915050610d1e565b5092915050565b60008181526001830160205260408120546144df57508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610d1e565b506000610d1e565b6000818152600183016020526040812054801561448757600061450b600183615adf565b855490915060009061451f90600190615adf565b905081811461443b5760008660000182815481106143f6576143f661595d565b803573ffffffffffffffffffffffffffffffffffffffff8116811461456357600080fd5b919050565b60008060006060848603121561457d57600080fd5b6145868461453f565b92506020840135915061459b6040850161453f565b90509250925092565b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461456357600080fd5b6000602082840312156145e657600080fd5b610bec826145a4565b60006020828403121561460157600080fd5b610bec8261453f565b6000815180845260005b8181101561463057602081850181015186830182015201614614565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000610bec602083018461460a565b6020808252825182820181905260009190848201906040850190845b818110156146cf57835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161469d565b50909695505050505050565b6000602082840312156146ed57600080fd5b813567ffffffffffffffff81111561470457600080fd5b820160408185031215610bec57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff8111828210171561476857614768614716565b60405290565b6040805190810167ffffffffffffffff8111828210171561476857614768614716565b604051610220810167ffffffffffffffff8111828210171561476857614768614716565b60405160c0810167ffffffffffffffff8111828210171561476857614768614716565b6040516060810167ffffffffffffffff8111828210171561476857614768614716565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561484257614842614716565b604052919050565b600067ffffffffffffffff82111561486457614864614716565b5060051b60200190565b801515811461132157600080fd5b80356145638161486e565b6000602080838503121561489a57600080fd5b823567ffffffffffffffff8111156148b157600080fd5b8301601f810185136148c257600080fd5b80356148d56148d08261484a565b6147fb565b81815260a091820283018401918482019190888411156148f457600080fd5b938501935b838510156149c75780858a0312156149115760008081fd5b614919614745565b6149228661453f565b8152868601357fffffffffffffffffffff00000000000000000000000000000000000000000000811681146149575760008081fd5b818801526040868101357fffff000000000000000000000000000000000000000000000000000000000000811681146149905760008081fd5b9082015260606149a187820161453f565b908201526080868101356149b48161486e565b90820152835293840193918501916148f9565b50979650505050505050565b803567ffffffffffffffff8116811461456357600080fd5b60008083601f8401126149fd57600080fd5b50813567ffffffffffffffff811115614a1557600080fd5b60208301915083602082850101111561204057600080fd5b60008083601f840112614a3f57600080fd5b50813567ffffffffffffffff811115614a5757600080fd5b6020830191508360208260051b850101111561204057600080fd5b600080600080600080600080600060c08a8c031215614a9057600080fd5b614a998a6149d3565b9850614aa760208b0161453f565b975060408a0135965060608a013567ffffffffffffffff80821115614acb57600080fd5b614ad78d838e016149eb565b909850965060808c0135915080821115614af057600080fd5b614afc8d838e01614a2d565b909650945060a08c0135915080821115614b1557600080fd5b818c0191508c601f830112614b2957600080fd5b813581811115614b3857600080fd5b8d60208260061b8501011115614b4d57600080fd5b6020830194508093505050509295985092959850929598565b848152600060208515158184015260806040840152614b88608084018661460a565b8381036060850152845180825282820190600581901b8301840184880160005b83811015614bf4577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868403018552614be283835161460a565b94870194925090860190600101614ba8565b50909b9a5050505050505050505050565b60008060208385031215614c1857600080fd5b823567ffffffffffffffff811115614c2f57600080fd5b614c3b85828601614a2d565b90969095509350505050565b602080825282518282018190526000919060409081850190868401855b82811015614cb557614ca584835180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16825260209081015163ffffffff16910152565b9284019290850190600101614c64565b5091979650505050505050565b600060208284031215614cd457600080fd5b610bec826149d3565b81517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16815260208083015163ffffffff169082015260408101610d1e565b803561ffff8116811461456357600080fd5b803563ffffffff8116811461456357600080fd5b60006020808385031215614d5157600080fd5b823567ffffffffffffffff811115614d6857600080fd5b8301601f81018513614d7957600080fd5b8035614d876148d08261484a565b8181526102409182028301840191848201919088841115614da757600080fd5b938501935b838510156149c75784890381811215614dc55760008081fd5b614dcd61476e565b614dd6876149d3565b8152610220807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe084011215614e0b5760008081fd5b614e13614791565b9250614e2089890161487c565b83526040614e2f818a01614d18565b8a8501526060614e40818b01614d2a565b8286015260809150614e53828b01614d2a565b9085015260a0614e648a8201614d2a565b8286015260c09150614e77828b01614d18565b9085015260e0614e888a8201614d2a565b828601526101009150614e9c828b01614d18565b90850152610120614eae8a8201614d18565b828601526101409150614ec2828b01614d18565b90850152610160614ed48a8201614d2a565b828601526101809150614ee8828b01614d2a565b908501526101a0614efa8a82016149d3565b828601526101c09150614f0e828b01614d2a565b908501526101e0614f208a8201614d2a565b828601526102009150614f34828b0161487c565b90850152614f438983016145a4565b90840152508088019190915283529384019391850191614dac565b81511515815261022081016020830151614f7e602084018261ffff169052565b506040830151614f96604084018263ffffffff169052565b506060830151614fae606084018263ffffffff169052565b506080830151614fc6608084018263ffffffff169052565b5060a0830151614fdc60a084018261ffff169052565b5060c0830151614ff460c084018263ffffffff169052565b5060e083015161500a60e084018261ffff169052565b506101008381015161ffff9081169184019190915261012080850151909116908301526101408084015163ffffffff90811691840191909152610160808501518216908401526101808085015167ffffffffffffffff16908401526101a0808501518216908401526101c080850151909116908301526101e080840151151590830152610200808401517fffffffff000000000000000000000000000000000000000000000000000000008116828501525b505092915050565b600082601f8301126150d557600080fd5b813560206150e56148d08361484a565b82815260069290921b8401810191818101908684111561510457600080fd5b8286015b8481101561515157604081890312156151215760008081fd5b61512961476e565b615132826149d3565b815261513f85830161453f565b81860152835291830191604001615108565b509695505050505050565b6000806040838503121561516f57600080fd5b67ffffffffffffffff8335111561518557600080fd5b83601f84358501011261519757600080fd5b6151a76148d0843585013561484a565b8335840180358083526020808401939260059290921b909101018610156151cd57600080fd5b602085358601015b85358601803560051b016020018110156153da5767ffffffffffffffff813511156151ff57600080fd5b8035863587010160407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0828a0301121561523857600080fd5b61524061476e565b61524c602083016149d3565b815267ffffffffffffffff6040830135111561526757600080fd5b88603f60408401358401011261527c57600080fd5b6152926148d0602060408501358501013561484a565b6020604084810135850182810135808552928401939260e00201018b10156152b957600080fd5b6040808501358501015b6040858101358601602081013560e00201018110156153bb5760e0818d0312156152ec57600080fd5b6152f461476e565b6152fd8261453f565b815260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0838f0301121561533157600080fd5b6153396147b5565b61534560208401614d2a565b815261535360408401614d2a565b602082015261536460608401614d18565b604082015261537560808401614d2a565b606082015261538660a08401614d2a565b608082015261539860c084013561486e565b60c083013560a0820152602082810191909152908452929092019160e0016152c3565b50806020840152505080855250506020830192506020810190506151d5565b5092505067ffffffffffffffff602084013511156153f757600080fd5b61540784602085013585016150c4565b90509250929050565b600082601f83011261542157600080fd5b813560206154316148d08361484a565b8083825260208201915060208460051b87010193508684111561545357600080fd5b602086015b84811015615151576154698161453f565b8352918301918301615458565b6000806040838503121561548957600080fd5b823567ffffffffffffffff808211156154a157600080fd5b6154ad86838701615410565b935060208501359150808211156154c357600080fd5b506154d085828601615410565b9150509250929050565b600080600080604085870312156154f057600080fd5b843567ffffffffffffffff8082111561550857600080fd5b615514888389016149eb565b9096509450602087013591508082111561552d57600080fd5b5061553a878288016149eb565b95989497509550505050565b6000806040838503121561555957600080fd5b615562836149d3565b91506154076020840161453f565b60006020828403121561558257600080fd5b813567ffffffffffffffff8082111561559a57600080fd5b90830190604082860312156155ae57600080fd5b6155b661476e565b8235828111156155c557600080fd5b6155d187828601615410565b8252506020830135828111156155e657600080fd5b6155f287828601615410565b60208301525095945050505050565b6000602080838503121561561457600080fd5b823567ffffffffffffffff81111561562b57600080fd5b8301601f8101851361563c57600080fd5b803561564a6148d08261484a565b81815260069190911b8201830190838101908783111561566957600080fd5b928401925b828410156156bb57604084890312156156875760008081fd5b61568f61476e565b6156988561453f565b81526156a58686016149d3565b818701528252604093909301929084019061566e565b979650505050505050565b600080604083850312156156d957600080fd5b6156e2836149d3565b9150602083013567ffffffffffffffff8111156156fe57600080fd5b830160a0818603121561571057600080fd5b809150509250929050565b60ff8116811461132157600080fd5b6000602080838503121561573d57600080fd5b823567ffffffffffffffff81111561575457600080fd5b8301601f8101851361576557600080fd5b80356157736148d08261484a565b81815260079190911b8201830190838101908783111561579257600080fd5b928401925b828410156156bb5783880360808112156157b15760008081fd5b6157b961476e565b6157c28661453f565b81526060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0840112156157f65760008081fd5b6157fe6147d8565b925061580b88880161453f565b835260408088013561581c8161571b565b848a0152908701359061582e8261486e565b8301528087019190915282526080939093019290840190615797565b6000806040838503121561585d57600080fd5b6158668361453f565b9150615407602084016149d3565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610d1e57610d1e615874565b6000826158f0577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261592a57600080fd5b83018035915067ffffffffffffffff82111561594557600080fd5b6020019150600681901b360382131561204057600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461456357600080fd5b6000604082840312156159ca57600080fd5b6159d261476e565b6159db8361453f565b81526159e96020840161598c565b60208201529392505050565b600060408284031215615a0757600080fd5b615a0f61476e565b6159db836149d3565b60006020808385031215615a2b57600080fd5b823567ffffffffffffffff811115615a4257600080fd5b8301601f81018513615a5357600080fd5b8035615a616148d08261484a565b81815260609182028301840191848201919088841115615a8057600080fd5b938501935b838510156149c75780858a031215615a9d5760008081fd5b615aa56147d8565b615aae8661453f565b8152615abb87870161598c565b878201526040615acc818801614d2a565b9082015283529384019391850191615a85565b81810381811115610d1e57610d1e615874565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615b2757600080fd5b83018035915067ffffffffffffffff821115615b4257600080fd5b60200191503681900382131561204057600080fd5b80820180821115610d1e57610d1e615874565b7fffffffff0000000000000000000000000000000000000000000000000000000081358181169160048510156150bc5760049490940360031b84901b1690921692915050565b60008085851115615bc057600080fd5b83861115615bcd57600080fd5b5050820193919092039150565b600060408284031215615bec57600080fd5b615bf461476e565b8251815260208301516159e98161486e565b600060208284031215615c1857600080fd5b5051919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61833603018112615c5357600080fd5b9190910192915050565b60ff8181168382160190811115610d1e57610d1e615874565b600181815b80851115615ccf57817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615cb557615cb5615874565b80851615615cc257918102915b93841c9390800290615c7b565b509250929050565b600082615ce657506001610d1e565b81615cf357506000610d1e565b8160018114615d095760028114615d1357615d2f565b6001915050610d1e565b60ff841115615d2457615d24615874565b50506001821b610d1e565b5060208310610133831016604e8410600b8410161715615d52575081810a610d1e565b615d5c8383615c76565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615d8e57615d8e615874565b029392505050565b6000610bec8383615cd7565b805169ffffffffffffffffffff8116811461456357600080fd5b600080600080600060a08688031215615dd457600080fd5b615ddd86615da2565b9450602086015193506040860151925060608601519150615e0060808701615da2565b90509295509295909350565b600060208284031215615e1e57600080fd5b8151610bec8161571b565b600060408284031215615e3b57600080fd5b615e4361476e565b615e4c8361453f565b8152602083013560208201528091505092915050565b63ffffffff81811683821601908082111561449157614491615874565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000818000a", + Bin: "0x60e06040523480156200001157600080fd5b5060405162007a7938038062007a7983398101604081905262000034916200189c565b85336000816200005757604051639b15e16f60e01b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b03848116919091179091558116156200008a576200008a81620001d0565b5050604080518082018252828152815160008152602080820190935291810191909152620000b8906200024a565b5060208701516001600160a01b03161580620000dc575086516001600160601b0316155b80620000f05750604087015163ffffffff16155b156200010f5760405163d794ef9560e01b815260040160405180910390fd5b6020878101516001600160a01b031660a05287516001600160601b031660805260408089015163ffffffff1660c052805160008152918201905262000155908662000399565b6200016084620004e1565b6200016b81620005d9565b620001768262000a45565b60408051600080825260208201909252620001c391859190620001bc565b6040805180820190915260008082526020820152815260200190600190039081620001945790505b5062000b11565b5050505050505062001b5a565b336001600160a01b03821603620001fa57604051636d6c4ee560e11b815260040160405180910390fd5b600080546001600160a01b0319166001600160a01b03838116918217835560015460405192939116917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b602081015160005b8151811015620002da576000828281518110620002735762000273620019bb565b602090810291909101015190506200028d60028262000e97565b15620002d0576040516001600160a01b03821681527fc3803387881faad271c47728894e3e36fac830ffc8602ca6fc07733cbda775809060200160405180910390a15b5060010162000252565b50815160005b815181101562000393576000828281518110620003015762000301620019bb565b6020026020010151905060006001600160a01b0316816001600160a01b0316036200033f576040516342bcdf7f60e11b815260040160405180910390fd5b6200034c60028262000eb7565b506040516001600160a01b03821681527feb1b9b92e50b7f88f9ff25d56765095ac6e91540eee214906f4036a908ffbdef9060200160405180910390a150600101620002e0565b50505050565b60005b82518110156200043a57620003d8838281518110620003bf57620003bf620019bb565b6020026020010151600b62000ece60201b90919060201c565b156200043157828181518110620003f357620003f3620019bb565b60200260200101516001600160a01b03167f1795838dc8ab2ffc5f431a1729a6afa0b587f982f7b2be0b9d7187a1ef547f9160405160405180910390a25b6001016200039c565b5060005b8151811015620004dc576200047a828281518110620004615762000461620019bb565b6020026020010151600b62000eb760201b90919060201c565b15620004d357818181518110620004955762000495620019bb565b60200260200101516001600160a01b03167fdf1b1bd32a69711488d71554706bb130b1fc63a5fa1a2cd85e8440f84065ba2360405160405180910390a25b6001016200043e565b505050565b60005b8151811015620005d5576000828281518110620005055762000505620019bb565b6020908102919091018101518051818301516001600160a01b0380831660008181526007875260409081902084518154868a0180518589018051949098166001600160a81b03199093168317600160a01b60ff928316021760ff60a81b1916600160a81b9415159490940293909317909355835190815291511697810197909752915115159186019190915292945090929091907fe6a7a17d710bf0b2cd05e5397dc6f97a5da4ee79e31e234bf5f965ee2bd9a5bf9060600160405180910390a2505050806001019050620004e4565b5050565b60005b8151811015620005d5576000828281518110620005fd57620005fd620019bb565b6020026020010151905060008383815181106200061e576200061e620019bb565b6020026020010151600001519050600082602001519050816001600160401b03166000148062000657575061016081015163ffffffff16155b806200067957506102008101516001600160e01b031916630a04b54b60e21b14155b80620006995750806060015163ffffffff1681610160015163ffffffff16115b15620006c85760405163c35aa79d60e01b81526001600160401b03831660048201526024015b60405180910390fd5b6001600160401b038216600090815260096020526040812060010154600160a81b900460e01b6001600160e01b03191690036200074857816001600160401b03167f525e3d4e0c31cef19cf9426af8d2c0ddd2d576359ca26bed92aac5fadda46265826040516200073a9190620019d1565b60405180910390a26200078c565b816001600160401b03167f283b699f411baff8f1c29fe49f32a828c8151596244b8e7e4c164edd6569a83582604051620007839190620019d1565b60405180910390a25b8060096000846001600160401b03166001600160401b0316815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548161ffff021916908361ffff16021790555060408201518160000160036101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160076101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600b6101000a81548163ffffffff021916908363ffffffff16021790555060a082015181600001600f6101000a81548161ffff021916908361ffff16021790555060c08201518160000160116101000a81548163ffffffff021916908363ffffffff16021790555060e08201518160000160156101000a81548161ffff021916908361ffff1602179055506101008201518160000160176101000a81548161ffff021916908361ffff1602179055506101208201518160000160196101000a81548161ffff021916908361ffff16021790555061014082015181600001601b6101000a81548163ffffffff021916908363ffffffff1602179055506101608201518160010160006101000a81548163ffffffff021916908363ffffffff1602179055506101808201518160010160046101000a8154816001600160401b0302191690836001600160401b031602179055506101a082015181600101600c6101000a81548163ffffffff021916908363ffffffff1602179055506101c08201518160010160106101000a81548163ffffffff021916908363ffffffff1602179055506101e08201518160010160146101000a81548160ff0219169083151502179055506102008201518160010160156101000a81548163ffffffff021916908360e01c0217905550905050505050806001019050620005dc565b60005b8151811015620005d557600082828151811062000a695762000a69620019bb565b6020026020010151600001519050600083838151811062000a8e5762000a8e620019bb565b6020908102919091018101518101516001600160a01b03841660008181526008845260409081902080546001600160401b0319166001600160401b0385169081179091559051908152919350917fbb77da6f7210cdd16904228a9360133d1d7dfff99b1bc75f128da5b53e28f97d910160405180910390a2505060010162000a48565b60005b825181101562000dd157600083828151811062000b355762000b35620019bb565b6020026020010151905060008160000151905060005b82602001515181101562000dc25760008360200151828151811062000b745762000b74620019bb565b602002602001015160200151905060008460200151838151811062000b9d5762000b9d620019bb565b6020026020010151600001519050816020015163ffffffff16826000015163ffffffff161062000bf857815160208301516040516305a7b3d160e11b815263ffffffff928316600482015291166024820152604401620006bf565b602063ffffffff16826080015163ffffffff16101562000c495760808201516040516312766e0160e11b81526001600160a01b038316600482015263ffffffff9091166024820152604401620006bf565b6001600160401b0384166000818152600a602090815260408083206001600160a01b0386168085529083529281902086518154938801518389015160608a015160808b015160a08c01511515600160901b0260ff60901b1963ffffffff928316600160701b021664ffffffffff60701b199383166a01000000000000000000000263ffffffff60501b1961ffff90961668010000000000000000029590951665ffffffffffff60401b19968416640100000000026001600160401b0319909b16939097169290921798909817939093169390931717919091161792909217909155519091907f94967ae9ea7729ad4f54021c1981765d2b1d954f7c92fbec340aa0a54f46b8b59062000daf908690600060c08201905063ffffffff80845116835280602085015116602084015261ffff60408501511660408401528060608501511660608401528060808501511660808401525060a0830151151560a083015292915050565b60405180910390a3505060010162000b4b565b50505080600101905062000b14565b5060005b8151811015620004dc57600082828151811062000df65762000df6620019bb565b6020026020010151600001519050600083838151811062000e1b5762000e1b620019bb565b6020908102919091018101518101516001600160401b0384166000818152600a845260408082206001600160a01b038516808452955280822080546001600160981b03191690555192945090917f4de5b1bcbca6018c11303a2c3f4a4b4f22a1c741d8c4ba430d246ac06c5ddf8b9190a3505060010162000dd5565b600062000eae836001600160a01b03841662000ee5565b90505b92915050565b600062000eae836001600160a01b03841662000fe9565b600062000eae836001600160a01b0384166200103b565b6000818152600183016020526040812054801562000fde57600062000f0c60018362001b22565b855490915060009062000f229060019062001b22565b905081811462000f8e57600086600001828154811062000f465762000f46620019bb565b906000526020600020015490508087600001848154811062000f6c5762000f6c620019bb565b6000918252602080832090910192909255918252600188019052604090208390555b855486908062000fa25762000fa262001b44565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505062000eb1565b600091505062000eb1565b6000818152600183016020526040812054620010325750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000eb1565b50600062000eb1565b6000818152600183016020526040812054801562000fde5760006200106260018362001b22565b8554909150600090620010789060019062001b22565b905080821462000f8e57600086600001828154811062000f465762000f46620019bb565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715620010d757620010d76200109c565b60405290565b604080519081016001600160401b0381118282101715620010d757620010d76200109c565b60405160c081016001600160401b0381118282101715620010d757620010d76200109c565b60405161022081016001600160401b0381118282101715620010d757620010d76200109c565b604051601f8201601f191681016001600160401b03811182821017156200117857620011786200109c565b604052919050565b80516001600160a01b03811681146200119857600080fd5b919050565b805163ffffffff811681146200119857600080fd5b600060608284031215620011c557600080fd5b620011cf620010b2565b82519091506001600160601b0381168114620011ea57600080fd5b8152620011fa6020830162001180565b60208201526200120d604083016200119d565b604082015292915050565b60006001600160401b038211156200123457620012346200109c565b5060051b60200190565b600082601f8301126200125057600080fd5b8151602062001269620012638362001218565b6200114d565b8083825260208201915060208460051b8701019350868411156200128c57600080fd5b602086015b84811015620012b357620012a58162001180565b835291830191830162001291565b509695505050505050565b805180151581146200119857600080fd5b600082601f830112620012e157600080fd5b81516020620012f4620012638362001218565b82815260079290921b840181019181810190868411156200131457600080fd5b8286015b84811015620012b3578088036080811215620013345760008081fd5b6200133e620010dd565b620013498362001180565b8152606080601f1984011215620013605760008081fd5b6200136a620010b2565b92506200137987850162001180565b835260408085015160ff81168114620013925760008081fd5b84890152620013a3858301620012be565b90840152508086019190915283529183019160800162001318565b80516001600160401b03811681146200119857600080fd5b805161ffff811681146200119857600080fd5b600082601f830112620013fb57600080fd5b815160206200140e620012638362001218565b82815260059290921b840181019181810190868411156200142e57600080fd5b8286015b84811015620012b35780516001600160401b03808211156200145357600080fd5b908801906040601f19838c0381018213156200146e57600080fd5b62001478620010dd565b62001485898601620013be565b815282850151848111156200149957600080fd5b8086019550508c603f860112620014af57600080fd5b888501519350620014c4620012638562001218565b84815260e09094028501830193898101908e861115620014e357600080fd5b958401955b85871015620015bc57868f0360e08112156200150357600080fd5b6200150d620010dd565b620015188962001180565b815260c086830112156200152b57600080fd5b6200153562001102565b9150620015448d8a016200119d565b825262001553878a016200119d565b8d8301526200156560608a01620013d6565b878301526200157760808a016200119d565b60608301526200158a60a08a016200119d565b60808301526200159d60c08a01620012be565b60a0830152808d0191909152825260e09690960195908a0190620014e8565b828b01525087525050509284019250830162001432565b600082601f830112620015e557600080fd5b81516020620015f8620012638362001218565b82815260069290921b840181019181810190868411156200161857600080fd5b8286015b84811015620012b35760408189031215620016375760008081fd5b62001641620010dd565b6200164c8262001180565b81526200165b858301620013be565b818601528352918301916040016200161c565b80516001600160e01b0319811681146200119857600080fd5b600082601f8301126200169957600080fd5b81516020620016ac620012638362001218565b8281526102409283028501820192828201919087851115620016cd57600080fd5b8387015b858110156200188f5780890382811215620016ec5760008081fd5b620016f6620010dd565b6200170183620013be565b815261022080601f1984011215620017195760008081fd5b6200172362001127565b925062001732888501620012be565b8352604062001743818601620013d6565b898501526060620017568187016200119d565b82860152608091506200176b8287016200119d565b9085015260a06200177e8682016200119d565b8286015260c0915062001793828701620013d6565b9085015260e0620017a68682016200119d565b828601526101009150620017bc828701620013d6565b90850152610120620017d0868201620013d6565b828601526101409150620017e6828701620013d6565b90850152610160620017fa8682016200119d565b828601526101809150620018108287016200119d565b908501526101a062001824868201620013be565b828601526101c091506200183a8287016200119d565b908501526101e06200184e8682016200119d565b82860152610200915062001864828701620012be565b90850152620018758583016200166e565b9084015250808701919091528452928401928101620016d1565b5090979650505050505050565b6000806000806000806000610120888a031215620018b957600080fd5b620018c58989620011b2565b60608901519097506001600160401b0380821115620018e357600080fd5b620018f18b838c016200123e565b975060808a01519150808211156200190857600080fd5b620019168b838c016200123e565b965060a08a01519150808211156200192d57600080fd5b6200193b8b838c01620012cf565b955060c08a01519150808211156200195257600080fd5b620019608b838c01620013e9565b945060e08a01519150808211156200197757600080fd5b620019858b838c01620015d3565b93506101008a01519150808211156200199d57600080fd5b50620019ac8a828b0162001687565b91505092959891949750929550565b634e487b7160e01b600052603260045260246000fd5b81511515815261022081016020830151620019f2602084018261ffff169052565b50604083015162001a0b604084018263ffffffff169052565b50606083015162001a24606084018263ffffffff169052565b50608083015162001a3d608084018263ffffffff169052565b5060a083015162001a5460a084018261ffff169052565b5060c083015162001a6d60c084018263ffffffff169052565b5060e083015162001a8460e084018261ffff169052565b506101008381015161ffff9081169184019190915261012080850151909116908301526101408084015163ffffffff9081169184019190915261016080850151821690840152610180808501516001600160401b0316908401526101a0808501518216908401526101c080850151909116908301526101e080840151151590830152610200928301516001600160e01b031916929091019190915290565b8181038181111562000eb157634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603160045260246000fd5b60805160a05160c051615ecc62001bad6000396000818161032801526119170152600081816102ec0152818161103401526110940152600081816102b8015281816110bd015261112d0152615ecc6000f3fe608060405234801561001057600080fd5b50600436106101e45760003560e01c8063770e2dc41161010f578063bf78e03f116100a2578063d8694ccd11610071578063d8694ccd14610b04578063f2fde38b14610b17578063fbe3f77814610b2a578063ffdb4b3714610b3d57600080fd5b8063bf78e03f14610a03578063cdc73d5114610ae1578063d02641a014610ae9578063d63d3af214610afc57600080fd5b806382b49eb0116100de57806382b49eb0146108455780638da5cb5b146109b557806391a2749a146109dd578063a69c64c0146109f057600080fd5b8063770e2dc41461080457806379ba5097146108175780637afac3221461081f578063805f21321461083257600080fd5b80633937306f116101875780634ab35b0b116101565780634ab35b0b14610472578063514e8cff146104b25780636cb5f3dd146105555780636def4ce71461056857600080fd5b80633937306f1461040757806341ed29e71461041c578063430d138c1461042f57806345ac924d1461045257600080fd5b806306285c69116101c357806306285c691461028b578063181f5a77146103a15780632451a627146103ea578063325c868e146103ff57600080fd5b806241e5be146101e957806301ffc9a71461020f578063061877e314610232575b600080fd5b6101fc6101f7366004614579565b610b85565b6040519081526020015b60405180910390f35b61022261021d3660046145e5565b610bf3565b6040519015158152602001610206565b610272610240366004614600565b73ffffffffffffffffffffffffffffffffffffffff1660009081526008602052604090205467ffffffffffffffff1690565b60405167ffffffffffffffff9091168152602001610206565b610355604080516060810182526000808252602082018190529181019190915260405180606001604052807f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1681526020017f000000000000000000000000000000000000000000000000000000000000000063ffffffff16815250905090565b6040805182516bffffffffffffffffffffffff16815260208084015173ffffffffffffffffffffffffffffffffffffffff16908201529181015163ffffffff1690820152606001610206565b6103dd6040518060400160405280601381526020017f46656551756f74657220312e362e302d6465760000000000000000000000000081525081565b604051610206919061467f565b6103f2610d24565b6040516102069190614692565b6101fc602481565b61041a6104153660046146ec565b610d35565b005b61041a61042a366004614898565b610fea565b61044261043d366004614a83565b61102c565b6040516102069493929190614b77565b610465610460366004614c16565b61123c565b6040516102069190614c58565b610485610480366004614600565b611305565b6040517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff9091168152602001610206565b6105486104c0366004614cd3565b60408051808201909152600080825260208201525067ffffffffffffffff166000908152600560209081526040918290208251808401909352547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811683527c0100000000000000000000000000000000000000000000000000000000900463ffffffff169082015290565b6040516102069190614cee565b61041a610563366004614d4f565b611310565b6107f7610576366004614cd3565b6040805161022081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081018290526101e081018290526102008101919091525067ffffffffffffffff908116600090815260096020908152604091829020825161022081018452815460ff8082161515835261ffff61010080840482169685019690965263ffffffff630100000084048116978501979097526701000000000000008304871660608501526b0100000000000000000000008304871660808501526f010000000000000000000000000000008304811660a0850152710100000000000000000000000000000000008304871660c08501527501000000000000000000000000000000000000000000808404821660e08087019190915277010000000000000000000000000000000000000000000000850483169786019790975279010000000000000000000000000000000000000000000000000084049091166101208501527b01000000000000000000000000000000000000000000000000000000909204861661014084015260019093015480861661016084015264010000000081049096166101808301526c01000000000000000000000000860485166101a083015270010000000000000000000000000000000086049094166101c082015274010000000000000000000000000000000000000000850490911615156101e08201527fffffffff0000000000000000000000000000000000000000000000000000000092909304901b1661020082015290565b6040516102069190614f6f565b61041a61081236600461516d565b611324565b61041a611336565b61041a61082d366004615487565b611404565b61041a6108403660046154eb565b611416565b610955610853366004615557565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a08101919091525067ffffffffffffffff919091166000908152600a6020908152604080832073ffffffffffffffffffffffffffffffffffffffff94909416835292815290829020825160c081018452905463ffffffff8082168352640100000000820481169383019390935268010000000000000000810461ffff16938201939093526a01000000000000000000008304821660608201526e01000000000000000000000000000083049091166080820152720100000000000000000000000000000000000090910460ff16151560a082015290565b6040516102069190600060c08201905063ffffffff80845116835280602085015116602084015261ffff60408501511660408401528060608501511660608401528060808501511660808401525060a0830151151560a083015292915050565b60015460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610206565b61041a6109eb366004615581565b611852565b61041a6109fe366004615612565b611863565b610aa4610a11366004614600565b60408051606080820183526000808352602080840182905292840181905273ffffffffffffffffffffffffffffffffffffffff9485168152600783528390208351918201845254938416815260ff74010000000000000000000000000000000000000000850481169282019290925275010000000000000000000000000000000000000000009093041615159082015290565b60408051825173ffffffffffffffffffffffffffffffffffffffff16815260208084015160ff169082015291810151151590820152606001610206565b6103f2611874565b610548610af7366004614600565b611880565b6101fc601281565b6101fc610b123660046156d7565b611a35565b61041a610b25366004614600565b611f7e565b61041a610b3836600461573b565b611f8f565b610b50610b4b36600461585b565b611fa0565b604080517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff938416815292909116602083015201610206565b6000610b9082612058565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16610bb785612058565b610bdf907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16856158b4565b610be991906158cb565b90505b9392505050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f805f2132000000000000000000000000000000000000000000000000000000001480610c8657507fffffffff0000000000000000000000000000000000000000000000000000000082167f9b645f4100000000000000000000000000000000000000000000000000000000145b80610cd257507fffffffff0000000000000000000000000000000000000000000000000000000082167f181f5a7700000000000000000000000000000000000000000000000000000000145b80610d1e57507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b92915050565b6060610d3060026120f2565b905090565b610d3d6120ff565b6000610d498280615906565b9050905060005b81811015610e93576000610d648480615906565b83818110610d7457610d7461596e565b905060400201803603810190610d8a91906159c9565b604080518082018252602080840180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff908116845263ffffffff42818116858701908152885173ffffffffffffffffffffffffffffffffffffffff9081166000908152600690975295889020965190519092167c010000000000000000000000000000000000000000000000000000000002919092161790935584519051935194955016927f52f50aa6d1a95a4595361ecf953d095f125d442e4673716dede699e049de148a92610e829290917bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b60405180910390a250600101610d50565b506000610ea36020840184615906565b9050905060005b81811015610fe4576000610ec16020860186615906565b83818110610ed157610ed161596e565b905060400201803603810190610ee79190615a06565b604080518082018252602080840180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff908116845263ffffffff42818116858701908152885167ffffffffffffffff9081166000908152600590975295889020965190519092167c010000000000000000000000000000000000000000000000000000000002919092161790935584519051935194955016927fdd84a3fa9ef9409f550d54d6affec7e9c480c878c6ab27b78912a03e1b371c6e92610fd39290917bffffffffffffffffffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b60405180910390a250600101610eaa565b50505050565b610ff2612144565b60005b8151811015611028576110208282815181106110135761101361596e565b6020026020010151612195565b600101610ff5565b5050565b6000806060807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168c73ffffffffffffffffffffffffffffffffffffffff160361108d578a93506110bb565b6110b88c8c7f0000000000000000000000000000000000000000000000000000000000000000610b85565b93505b7f00000000000000000000000000000000000000000000000000000000000000006bffffffffffffffffffffffff1684111561115f576040517f6a92a483000000000000000000000000000000000000000000000000000000008152600481018590526bffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660248201526044015b60405180910390fd5b67ffffffffffffffff8d1660009081526009602052604081206001015463ffffffff169061118e8c8c84612367565b9050806020015194506111a48f8b8b8b8b612510565b92508585611224836040805182516024820152602092830151151560448083019190915282518083039091018152606490910190915290810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f181dcf100000000000000000000000000000000000000000000000000000000017905290565b95509550955050509950995099509995505050505050565b60608160008167ffffffffffffffff81111561125a5761125a614727565b60405190808252806020026020018201604052801561129f57816020015b60408051808201909152600080825260208201528152602001906001900390816112785790505b50905060005b828110156112fc576112d78686838181106112c2576112c261596e565b9050602002016020810190610af79190614600565b8282815181106112e9576112e961596e565b60209081029190910101526001016112a5565b50949350505050565b6000610d1e82612058565b611318612144565b61132181612893565b50565b61132c612144565b6110288282612d65565b60005473ffffffffffffffffffffffffffffffffffffffff163314611387576040517f02b543c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000008082163390811790935560008054909116815560405173ffffffffffffffffffffffffffffffffffffffff909216929183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b61140c612144565b61102882826131db565b600080600061145a87878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061332292505050565b92509250925061146c3383858461333d565b600061147a85870187615a29565b905060005b8151811015611847576000600760008484815181106114a0576114a061596e565b6020908102919091018101515173ffffffffffffffffffffffffffffffffffffffff908116835282820193909352604091820160002082516060810184529054938416815260ff740100000000000000000000000000000000000000008504811692820192909252750100000000000000000000000000000000000000000090930416151590820181905290915061159b578282815181106115445761154461596e565b6020908102919091010151516040517f06439c6b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401611156565b60006115e8601283602001518686815181106115b9576115b961596e565b6020026020010151602001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16613495565b9050600660008585815181106116005761160061596e565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001601c9054906101000a900463ffffffff1663ffffffff168484815181106116725761167261596e565b60200260200101516040015163ffffffff16101561169157505061183f565b6040518060400160405280827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1681526020018585815181106116d2576116d261596e565b60200260200101516040015163ffffffff16815250600660008686815181106116fd576116fd61596e565b6020908102919091018101515173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251929091015163ffffffff167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117905583518490849081106117955761179561596e565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff167f52f50aa6d1a95a4595361ecf953d095f125d442e4673716dede699e049de148a828686815181106117eb576117eb61596e565b6020026020010151604001516040516118349291907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff92909216825263ffffffff16602082015260400190565b60405180910390a250505b60010161147f565b505050505050505050565b61185a612144565b61132181613558565b61186b612144565b611321816136e4565b6060610d30600b6120f2565b604080518082019091526000808252602082015273ffffffffffffffffffffffffffffffffffffffff82166000908152600660209081526040918290208251808401909352547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116835263ffffffff7c010000000000000000000000000000000000000000000000000000000090910481169183018290527f000000000000000000000000000000000000000000000000000000000000000016906119429042615af0565b101561194e5792915050565b73ffffffffffffffffffffffffffffffffffffffff80841660009081526007602090815260409182902082516060810184529054938416815260ff74010000000000000000000000000000000000000000850481169282019290925275010000000000000000000000000000000000000000009093041615801591830191909152806119ef5750805173ffffffffffffffffffffffffffffffffffffffff16155b156119fb575092915050565b6000611a06826137ce565b9050826020015163ffffffff16816020015163ffffffff161015611a2a5782611a2c565b805b95945050505050565b67ffffffffffffffff8083166000908152600960209081526040808320815161022081018352815460ff808216151580845261ffff61010080850482169886019890985263ffffffff630100000085048116978601979097526701000000000000008404871660608601526b0100000000000000000000008404871660808601526f010000000000000000000000000000008404811660a0860152710100000000000000000000000000000000008404871660c08601527501000000000000000000000000000000000000000000808504821660e08088019190915277010000000000000000000000000000000000000000000000860483169987019990995279010000000000000000000000000000000000000000000000000085049091166101208601527b01000000000000000000000000000000000000000000000000000000909304861661014085015260019094015480861661016085015264010000000081049098166101808401526c01000000000000000000000000880485166101a084015270010000000000000000000000000000000088049094166101c083015274010000000000000000000000000000000000000000870490931615156101e08201527fffffffff000000000000000000000000000000000000000000000000000000009290950490921b16610200840152909190611c6f576040517f99ac52f200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff85166004820152602401611156565b611c8a611c826080850160608601614600565b600b90613960565b611ce957611c9e6080840160608501614600565b6040517f2502348c00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401611156565b6000611cf86040850185615906565b9150611d54905082611d0d6020870187615b03565b905083611d1a8880615b03565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061398f92505050565b6000611d6e611d696080870160608801614600565b612058565b90506000611d8187856101c00151613a4c565b9050600080808515611dc157611db5878b611da260808d0160608e01614600565b88611db060408f018f615906565b613b4c565b91945092509050611de1565b6101a0870151611dde9063ffffffff16662386f26fc100006158b4565b92505b61010087015160009061ffff1615611e2557611e22886dffffffffffffffffffffffffffff607088901c16611e1960208e018e615b03565b90508a86613e24565b90505b61018088015160009067ffffffffffffffff16611e4e611e4860808e018e615b03565b8c613ed4565b600001518563ffffffff168b60a0015161ffff168663ffffffff168f8060200190611e799190615b03565b611e84929150615b68565b611e8e91906158b4565b8c6080015163ffffffff16611ea39190615b68565b611ead9190615b68565b611eb79190615b68565b611ed1906dffffffffffffffffffffffffffff89166158b4565b611edb91906158b4565b9050867bffffffffffffffffffffffffffffffffffffffffffffffffffffffff168282600860008f6060016020810190611f159190614600565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002054611f509067ffffffffffffffff16896158b4565b611f5a9190615b68565b611f649190615b68565b611f6e91906158cb565b9c9b505050505050505050505050565b611f86612144565b61132181613f95565b611f97612144565b61132181614059565b67ffffffffffffffff8116600090815260096020526040812054819060ff16612001576040517f99ac52f200000000000000000000000000000000000000000000000000000000815267ffffffffffffffff84166004820152602401611156565b61200a84612058565b67ffffffffffffffff841660009081526009602052604090206001015461204c908590700100000000000000000000000000000000900463ffffffff16613a4c565b915091505b9250929050565b60008061206483611880565b9050806020015163ffffffff166000148061209c575080517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16155b156120eb576040517f06439c6b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152602401611156565b5192915050565b60606000610bec836141ab565b61210a600233613960565b612142576040517fd86ad9cf000000000000000000000000000000000000000000000000000000008152336004820152602401611156565b565b60015473ffffffffffffffffffffffffffffffffffffffff163314612142576040517f2b5c74de00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061224e82600001518360600151846020015185604001516040805173ffffffffffffffffffffffffffffffffffffffff80871660208301528516918101919091527fffffffffffffffffffff00000000000000000000000000000000000000000000831660608201527fffff0000000000000000000000000000000000000000000000000000000000008216608082015260009060a001604051602081830303815290604052805190602001209050949350505050565b60808301516000828152600460205260409081902080549215157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00909316929092179091555190915081907f32a4ba3fa3351b11ad555d4c8ec70a744e8705607077a946807030d64b6ab1a39061235b908590600060a08201905073ffffffffffffffffffffffffffffffffffffffff8084511683527fffffffffffffffffffff0000000000000000000000000000000000000000000060208501511660208401527fffff00000000000000000000000000000000000000000000000000000000000060408501511660408401528060608501511660608401525060808301511515608083015292915050565b60405180910390a25050565b604080518082019091526000808252602082015260008390036123a857506040805180820190915267ffffffffffffffff8216815260006020820152610bec565b60006123b48486615b7b565b905060006123c58560048189615bc1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293505050507fffffffff0000000000000000000000000000000000000000000000000000000082167fe7e230f0000000000000000000000000000000000000000000000000000000000161246257808060200190518101906124599190615beb565b92505050610bec565b7f6859a837000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316016124de576040518060400160405280828060200190518101906124ca9190615c17565b815260006020909101529250610bec915050565b6040517f5247fdce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff808616600090815260096020526040902060010154606091750100000000000000000000000000000000000000000090910460e01b90859081111561256057612560614727565b60405190808252806020026020018201604052801561259357816020015b606081526020019060019003908161257e5790505b50915060005b858110156128885760008585838181106125b5576125b561596e565b6125cb9260206040909202019081019150614600565b905060008888848181106125e1576125e161596e565b90506020028101906125f39190615c30565b612601906040810190615b03565b91505060208111156126b15767ffffffffffffffff8a166000908152600a6020908152604080832073ffffffffffffffffffffffffffffffffffffffff861684529091529020546e010000000000000000000000000000900463ffffffff168111156126b1576040517f36f536ca00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83166004820152602401611156565b612721848a8a868181106126c7576126c761596e565b90506020028101906126d99190615c30565b6126e7906020810190615b03565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061420792505050565b67ffffffffffffffff8a166000908152600a6020908152604080832073ffffffffffffffffffffffffffffffffffffffff861684528252808320815160c081018352905463ffffffff8082168352640100000000820481169483019490945268010000000000000000810461ffff16928201929092526a01000000000000000000008204831660608201526e010000000000000000000000000000820490921660808301527201000000000000000000000000000000000000900460ff16151560a082018190529091906128335767ffffffffffffffff8c166000908152600960205260409020547b01000000000000000000000000000000000000000000000000000000900463ffffffff16612839565b81606001515b6040805163ffffffff831660208201529192500160405160208183030381529060405287868151811061286e5761286e61596e565b602002602001018190525050505050806001019050612599565b505095945050505050565b60005b81518110156110285760008282815181106128b3576128b361596e565b6020026020010151905060008383815181106128d1576128d161596e565b60200260200101516000015190506000826020015190508167ffffffffffffffff166000148061290a575061016081015163ffffffff16155b8061295c57506102008101517fffffffff00000000000000000000000000000000000000000000000000000000167f2812d52c0000000000000000000000000000000000000000000000000000000014155b8061297b5750806060015163ffffffff1681610160015163ffffffff16115b156129be576040517fc35aa79d00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff83166004820152602401611156565b67ffffffffffffffff82166000908152600960205260408120600101547501000000000000000000000000000000000000000000900460e01b7fffffffff00000000000000000000000000000000000000000000000000000000169003612a66578167ffffffffffffffff167f525e3d4e0c31cef19cf9426af8d2c0ddd2d576359ca26bed92aac5fadda4626582604051612a599190614f6f565b60405180910390a2612aa9565b8167ffffffffffffffff167f283b699f411baff8f1c29fe49f32a828c8151596244b8e7e4c164edd6569a83582604051612aa09190614f6f565b60405180910390a25b80600960008467ffffffffffffffff1667ffffffffffffffff16815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548161ffff021916908361ffff16021790555060408201518160000160036101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160076101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600b6101000a81548163ffffffff021916908363ffffffff16021790555060a082015181600001600f6101000a81548161ffff021916908361ffff16021790555060c08201518160000160116101000a81548163ffffffff021916908363ffffffff16021790555060e08201518160000160156101000a81548161ffff021916908361ffff1602179055506101008201518160000160176101000a81548161ffff021916908361ffff1602179055506101208201518160000160196101000a81548161ffff021916908361ffff16021790555061014082015181600001601b6101000a81548163ffffffff021916908363ffffffff1602179055506101608201518160010160006101000a81548163ffffffff021916908363ffffffff1602179055506101808201518160010160046101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506101a082015181600101600c6101000a81548163ffffffff021916908363ffffffff1602179055506101c08201518160010160106101000a81548163ffffffff021916908363ffffffff1602179055506101e08201518160010160146101000a81548160ff0219169083151502179055506102008201518160010160156101000a81548163ffffffff021916908360e01c0217905550905050505050806001019050612896565b60005b82518110156130f2576000838281518110612d8557612d8561596e565b6020026020010151905060008160000151905060005b8260200151518110156130e457600083602001518281518110612dc057612dc061596e565b6020026020010151602001519050600084602001518381518110612de657612de661596e565b6020026020010151600001519050816020015163ffffffff16826000015163ffffffff1610612e5857815160208301516040517f0b4f67a200000000000000000000000000000000000000000000000000000000815263ffffffff928316600482015291166024820152604401611156565b602063ffffffff16826080015163ffffffff161015612ecd5760808201516040517f24ecdc0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316600482015263ffffffff9091166024820152604401611156565b67ffffffffffffffff84166000818152600a6020908152604080832073ffffffffffffffffffffffffffffffffffffffff86168085529083529281902086518154938801518389015160608a015160808b015160a08c015115157201000000000000000000000000000000000000027fffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffff63ffffffff9283166e01000000000000000000000000000002167fffffffffffffffffffffffffff0000000000ffffffffffffffffffffffffffff9383166a0100000000000000000000027fffffffffffffffffffffffffffffffffffff00000000ffffffffffffffffffff61ffff9096166801000000000000000002959095167fffffffffffffffffffffffffffffffffffff000000000000ffffffffffffffff968416640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b16939097169290921798909817939093169390931717919091161792909217909155519091907f94967ae9ea7729ad4f54021c1981765d2b1d954f7c92fbec340aa0a54f46b8b5906130d2908690600060c08201905063ffffffff80845116835280602085015116602084015261ffff60408501511660408401528060608501511660608401528060808501511660808401525060a0830151151560a083015292915050565b60405180910390a35050600101612d9b565b505050806001019050612d68565b5060005b81518110156131d65760008282815181106131135761311361596e565b602002602001015160000151905060008383815181106131355761313561596e565b60209081029190910181015181015167ffffffffffffffff84166000818152600a8452604080822073ffffffffffffffffffffffffffffffffffffffff8516808452955280822080547fffffffffffffffffffffffffff000000000000000000000000000000000000001690555192945090917f4de5b1bcbca6018c11303a2c3f4a4b4f22a1c741d8c4ba430d246ac06c5ddf8b9190a350506001016130f6565b505050565b60005b825181101561327e576132148382815181106131fc576131fc61596e565b6020026020010151600b61425990919063ffffffff16565b156132765782818151811061322b5761322b61596e565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167f1795838dc8ab2ffc5f431a1729a6afa0b587f982f7b2be0b9d7187a1ef547f9160405160405180910390a25b6001016131de565b5060005b81518110156131d6576132b88282815181106132a0576132a061596e565b6020026020010151600b61427b90919063ffffffff16565b1561331a578181815181106132cf576132cf61596e565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167fdf1b1bd32a69711488d71554706bb130b1fc63a5fa1a2cd85e8440f84065ba2360405160405180910390a25b600101613282565b6040810151604a820151605e90920151909260609290921c91565b6040805173ffffffffffffffffffffffffffffffffffffffff868116602080840191909152908616828401527fffffffffffffffffffff00000000000000000000000000000000000000000000851660608301527fffff00000000000000000000000000000000000000000000000000000000000084166080808401919091528351808403909101815260a09092018352815191810191909120600081815260049092529190205460ff1661348e576040517f097e17ff00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8087166004830152851660248201527fffffffffffffffffffff00000000000000000000000000000000000000000000841660448201527fffff00000000000000000000000000000000000000000000000000000000000083166064820152608401611156565b5050505050565b6000806134a28486615c6e565b9050600060248260ff1611156134dc576134c0602460ff8416615af0565b6134cb90600a615da7565b6134d590856158cb565b9050613502565b6134ea60ff83166024615af0565b6134f590600a615da7565b6134ff90856158b4565b90505b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811115611a2c576040517f10cb51d100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602081015160005b81518110156135f357600082828151811061357d5761357d61596e565b6020026020010151905061359b81600261429d90919063ffffffff16565b156135ea5760405173ffffffffffffffffffffffffffffffffffffffff821681527fc3803387881faad271c47728894e3e36fac830ffc8602ca6fc07733cbda775809060200160405180910390a15b50600101613560565b50815160005b8151811015610fe45760008282815181106136165761361661596e565b60200260200101519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603613686576040517f8579befe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61369160028261427b565b5060405173ffffffffffffffffffffffffffffffffffffffff821681527feb1b9b92e50b7f88f9ff25d56765095ac6e91540eee214906f4036a908ffbdef9060200160405180910390a1506001016135f9565b60005b81518110156110285760008282815181106137045761370461596e565b602002602001015160000151905060008383815181106137265761372661596e565b60209081029190910181015181015173ffffffffffffffffffffffffffffffffffffffff841660008181526008845260409081902080547fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000001667ffffffffffffffff85169081179091559051908152919350917fbb77da6f7210cdd16904228a9360133d1d7dfff99b1bc75f128da5b53e28f97d910160405180910390a250506001016136e7565b60408051808201909152600080825260208201526000826000015190506000808273ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015613839573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061385d9190615dcd565b50935050925050600082121561389f576040517f10cb51d100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061391e8473ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156138ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139139190615e1d565b876020015185613495565b604080518082019091527bffffffffffffffffffffffffffffffffffffffffffffffffffffffff909116815263ffffffff909216602083015250949350505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001830160205260408120541515610bec565b836040015163ffffffff168311156139e85760408085015190517f8693378900000000000000000000000000000000000000000000000000000000815263ffffffff909116600482015260248101849052604401611156565b836020015161ffff16821115613a3d5760208401516040517fd88dddd60000000000000000000000000000000000000000000000000000000081526004810184905261ffff9091166024820152604401611156565b610fe484610200015182614207565b67ffffffffffffffff821660009081526005602090815260408083208151808301909252547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116825263ffffffff7c010000000000000000000000000000000000000000000000000000000090910481169282019290925290831615613b44576000816020015163ffffffff1642613ae19190615af0565b90508363ffffffff16811115613b42576040517ff08bcb3e00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8616600482015263ffffffff8516602482015260448101829052606401611156565b505b519392505050565b6000808083815b81811015613e16576000878783818110613b6f57613b6f61596e565b905060400201803603810190613b859190615e3a565b67ffffffffffffffff8c166000908152600a60209081526040808320845173ffffffffffffffffffffffffffffffffffffffff168452825291829020825160c081018452905463ffffffff8082168352640100000000820481169383019390935268010000000000000000810461ffff16938201939093526a01000000000000000000008304821660608201526e01000000000000000000000000000083049091166080820152720100000000000000000000000000000000000090910460ff16151560a0820181905291925090613ca5576101208d0151613c729061ffff16662386f26fc100006158b4565b613c7c9088615b68565b96508c610140015186613c8f9190615e73565b9550613c9c602086615e73565b94505050613e0e565b604081015160009061ffff1615613d5e5760008c73ffffffffffffffffffffffffffffffffffffffff16846000015173ffffffffffffffffffffffffffffffffffffffff1614613d01578351613cfa90612058565b9050613d04565b508a5b620186a0836040015161ffff16613d468660200151847bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166142bf90919063ffffffff16565b613d5091906158b4565b613d5a91906158cb565b9150505b6060820151613d6d9088615e73565b9650816080015186613d7f9190615e73565b8251909650600090613d9e9063ffffffff16662386f26fc100006158b4565b905080821015613dbd57613db2818a615b68565b985050505050613e0e565b6000836020015163ffffffff16662386f26fc10000613ddc91906158b4565b905080831115613dfc57613df0818b615b68565b99505050505050613e0e565b613e06838b615b68565b995050505050505b600101613b53565b505096509650969350505050565b60008063ffffffff8316613e3a610120866158b4565b613e46876101e0615b68565b613e509190615b68565b613e5a9190615b68565b905060008760c0015163ffffffff168860e0015161ffff1683613e7d91906158b4565b613e879190615b68565b61010089015190915061ffff16613eae6dffffffffffffffffffffffffffff8916836158b4565b613eb891906158b4565b613ec890655af3107a40006158b4565b98975050505050505050565b60408051808201909152600080825260208201526000613f00858585610160015163ffffffff16612367565b9050826060015163ffffffff1681600001511115613f4a576040517f4c4fc93a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b826101e001518015613f5e57508060200151155b15610be9576040517fee433e9900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b3373ffffffffffffffffffffffffffffffffffffffff821603613fe4576040517fdad89dca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff838116918217835560015460405192939116917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60005b81518110156110285760008282815181106140795761407961596e565b60209081029190910181015180518183015173ffffffffffffffffffffffffffffffffffffffff80831660008181526007875260409081902084518154868a0180518589018051949098167fffffffffffffffffffffff00000000000000000000000000000000000000000090931683177401000000000000000000000000000000000000000060ff92831602177fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1675010000000000000000000000000000000000000000009415159490940293909317909355835190815291511697810197909752915115159186019190915292945090929091907fe6a7a17d710bf0b2cd05e5397dc6f97a5da4ee79e31e234bf5f965ee2bd9a5bf9060600160405180910390a250505080600101905061405c565b6060816000018054806020026020016040519081016040528092919081815260200182805480156141fb57602002820191906000526020600020905b8154815260200190600101908083116141e7575b50505050509050919050565b7fd7ed2ad4000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831601611028576131d6816142fc565b6000610bec8373ffffffffffffffffffffffffffffffffffffffff84166143af565b6000610bec8373ffffffffffffffffffffffffffffffffffffffff84166144a9565b6000610bec8373ffffffffffffffffffffffffffffffffffffffff84166144f8565b6000670de0b6b3a76400006142f2837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff86166158b4565b610bec91906158cb565b6000815160201461433b57816040517f8d666f60000000000000000000000000000000000000000000000000000000008152600401611156919061467f565b6000828060200190518101906143519190615c17565b905073ffffffffffffffffffffffffffffffffffffffff811180614376575061040081105b15610d1e57826040517f8d666f60000000000000000000000000000000000000000000000000000000008152600401611156919061467f565b600081815260018301602052604081205480156144985760006143d3600183615af0565b85549091506000906143e790600190615af0565b905080821461444c5760008660000182815481106144075761440761596e565b906000526020600020015490508087600001848154811061442a5761442a61596e565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061445d5761445d615e90565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610d1e565b6000915050610d1e565b5092915050565b60008181526001830160205260408120546144f057508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610d1e565b506000610d1e565b6000818152600183016020526040812054801561449857600061451c600183615af0565b855490915060009061453090600190615af0565b905081811461444c5760008660000182815481106144075761440761596e565b803573ffffffffffffffffffffffffffffffffffffffff8116811461457457600080fd5b919050565b60008060006060848603121561458e57600080fd5b61459784614550565b9250602084013591506145ac60408501614550565b90509250925092565b80357fffffffff000000000000000000000000000000000000000000000000000000008116811461457457600080fd5b6000602082840312156145f757600080fd5b610bec826145b5565b60006020828403121561461257600080fd5b610bec82614550565b6000815180845260005b8181101561464157602081850181015186830182015201614625565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b602081526000610bec602083018461461b565b6020808252825182820181905260009190848201906040850190845b818110156146e057835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016146ae565b50909695505050505050565b6000602082840312156146fe57600080fd5b813567ffffffffffffffff81111561471557600080fd5b820160408185031215610bec57600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff8111828210171561477957614779614727565b60405290565b6040805190810167ffffffffffffffff8111828210171561477957614779614727565b604051610220810167ffffffffffffffff8111828210171561477957614779614727565b60405160c0810167ffffffffffffffff8111828210171561477957614779614727565b6040516060810167ffffffffffffffff8111828210171561477957614779614727565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561485357614853614727565b604052919050565b600067ffffffffffffffff82111561487557614875614727565b5060051b60200190565b801515811461132157600080fd5b80356145748161487f565b600060208083850312156148ab57600080fd5b823567ffffffffffffffff8111156148c257600080fd5b8301601f810185136148d357600080fd5b80356148e66148e18261485b565b61480c565b81815260a0918202830184019184820191908884111561490557600080fd5b938501935b838510156149d85780858a0312156149225760008081fd5b61492a614756565b61493386614550565b8152868601357fffffffffffffffffffff00000000000000000000000000000000000000000000811681146149685760008081fd5b818801526040868101357fffff000000000000000000000000000000000000000000000000000000000000811681146149a15760008081fd5b9082015260606149b2878201614550565b908201526080868101356149c58161487f565b908201528352938401939185019161490a565b50979650505050505050565b803567ffffffffffffffff8116811461457457600080fd5b60008083601f840112614a0e57600080fd5b50813567ffffffffffffffff811115614a2657600080fd5b60208301915083602082850101111561205157600080fd5b60008083601f840112614a5057600080fd5b50813567ffffffffffffffff811115614a6857600080fd5b6020830191508360208260051b850101111561205157600080fd5b600080600080600080600080600060c08a8c031215614aa157600080fd5b614aaa8a6149e4565b9850614ab860208b01614550565b975060408a0135965060608a013567ffffffffffffffff80821115614adc57600080fd5b614ae88d838e016149fc565b909850965060808c0135915080821115614b0157600080fd5b614b0d8d838e01614a3e565b909650945060a08c0135915080821115614b2657600080fd5b818c0191508c601f830112614b3a57600080fd5b813581811115614b4957600080fd5b8d60208260061b8501011115614b5e57600080fd5b6020830194508093505050509295985092959850929598565b848152600060208515158184015260806040840152614b99608084018661461b565b8381036060850152845180825282820190600581901b8301840184880160005b83811015614c05577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0868403018552614bf383835161461b565b94870194925090860190600101614bb9565b50909b9a5050505050505050505050565b60008060208385031215614c2957600080fd5b823567ffffffffffffffff811115614c4057600080fd5b614c4c85828601614a3e565b90969095509350505050565b602080825282518282018190526000919060409081850190868401855b82811015614cc657614cb684835180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16825260209081015163ffffffff16910152565b9284019290850190600101614c75565b5091979650505050505050565b600060208284031215614ce557600080fd5b610bec826149e4565b81517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16815260208083015163ffffffff169082015260408101610d1e565b803561ffff8116811461457457600080fd5b803563ffffffff8116811461457457600080fd5b60006020808385031215614d6257600080fd5b823567ffffffffffffffff811115614d7957600080fd5b8301601f81018513614d8a57600080fd5b8035614d986148e18261485b565b8181526102409182028301840191848201919088841115614db857600080fd5b938501935b838510156149d85784890381811215614dd65760008081fd5b614dde61477f565b614de7876149e4565b8152610220807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe084011215614e1c5760008081fd5b614e246147a2565b9250614e3189890161488d565b83526040614e40818a01614d29565b8a8501526060614e51818b01614d3b565b8286015260809150614e64828b01614d3b565b9085015260a0614e758a8201614d3b565b8286015260c09150614e88828b01614d29565b9085015260e0614e998a8201614d3b565b828601526101009150614ead828b01614d29565b90850152610120614ebf8a8201614d29565b828601526101409150614ed3828b01614d29565b90850152610160614ee58a8201614d3b565b828601526101809150614ef9828b01614d3b565b908501526101a0614f0b8a82016149e4565b828601526101c09150614f1f828b01614d3b565b908501526101e0614f318a8201614d3b565b828601526102009150614f45828b0161488d565b90850152614f548983016145b5565b90840152508088019190915283529384019391850191614dbd565b81511515815261022081016020830151614f8f602084018261ffff169052565b506040830151614fa7604084018263ffffffff169052565b506060830151614fbf606084018263ffffffff169052565b506080830151614fd7608084018263ffffffff169052565b5060a0830151614fed60a084018261ffff169052565b5060c083015161500560c084018263ffffffff169052565b5060e083015161501b60e084018261ffff169052565b506101008381015161ffff9081169184019190915261012080850151909116908301526101408084015163ffffffff90811691840191909152610160808501518216908401526101808085015167ffffffffffffffff16908401526101a0808501518216908401526101c080850151909116908301526101e080840151151590830152610200808401517fffffffff000000000000000000000000000000000000000000000000000000008116828501525b505092915050565b600082601f8301126150e657600080fd5b813560206150f66148e18361485b565b82815260069290921b8401810191818101908684111561511557600080fd5b8286015b8481101561516257604081890312156151325760008081fd5b61513a61477f565b615143826149e4565b8152615150858301614550565b81860152835291830191604001615119565b509695505050505050565b6000806040838503121561518057600080fd5b67ffffffffffffffff8335111561519657600080fd5b83601f8435850101126151a857600080fd5b6151b86148e1843585013561485b565b8335840180358083526020808401939260059290921b909101018610156151de57600080fd5b602085358601015b85358601803560051b016020018110156153eb5767ffffffffffffffff8135111561521057600080fd5b8035863587010160407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0828a0301121561524957600080fd5b61525161477f565b61525d602083016149e4565b815267ffffffffffffffff6040830135111561527857600080fd5b88603f60408401358401011261528d57600080fd5b6152a36148e1602060408501358501013561485b565b6020604084810135850182810135808552928401939260e00201018b10156152ca57600080fd5b6040808501358501015b6040858101358601602081013560e00201018110156153cc5760e0818d0312156152fd57600080fd5b61530561477f565b61530e82614550565b815260c07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0838f0301121561534257600080fd5b61534a6147c6565b61535660208401614d3b565b815261536460408401614d3b565b602082015261537560608401614d29565b604082015261538660808401614d3b565b606082015261539760a08401614d3b565b60808201526153a960c084013561487f565b60c083013560a0820152602082810191909152908452929092019160e0016152d4565b50806020840152505080855250506020830192506020810190506151e6565b5092505067ffffffffffffffff6020840135111561540857600080fd5b61541884602085013585016150d5565b90509250929050565b600082601f83011261543257600080fd5b813560206154426148e18361485b565b8083825260208201915060208460051b87010193508684111561546457600080fd5b602086015b848110156151625761547a81614550565b8352918301918301615469565b6000806040838503121561549a57600080fd5b823567ffffffffffffffff808211156154b257600080fd5b6154be86838701615421565b935060208501359150808211156154d457600080fd5b506154e185828601615421565b9150509250929050565b6000806000806040858703121561550157600080fd5b843567ffffffffffffffff8082111561551957600080fd5b615525888389016149fc565b9096509450602087013591508082111561553e57600080fd5b5061554b878288016149fc565b95989497509550505050565b6000806040838503121561556a57600080fd5b615573836149e4565b915061541860208401614550565b60006020828403121561559357600080fd5b813567ffffffffffffffff808211156155ab57600080fd5b90830190604082860312156155bf57600080fd5b6155c761477f565b8235828111156155d657600080fd5b6155e287828601615421565b8252506020830135828111156155f757600080fd5b61560387828601615421565b60208301525095945050505050565b6000602080838503121561562557600080fd5b823567ffffffffffffffff81111561563c57600080fd5b8301601f8101851361564d57600080fd5b803561565b6148e18261485b565b81815260069190911b8201830190838101908783111561567a57600080fd5b928401925b828410156156cc57604084890312156156985760008081fd5b6156a061477f565b6156a985614550565b81526156b68686016149e4565b818701528252604093909301929084019061567f565b979650505050505050565b600080604083850312156156ea57600080fd5b6156f3836149e4565b9150602083013567ffffffffffffffff81111561570f57600080fd5b830160a0818603121561572157600080fd5b809150509250929050565b60ff8116811461132157600080fd5b6000602080838503121561574e57600080fd5b823567ffffffffffffffff81111561576557600080fd5b8301601f8101851361577657600080fd5b80356157846148e18261485b565b81815260079190911b820183019083810190878311156157a357600080fd5b928401925b828410156156cc5783880360808112156157c25760008081fd5b6157ca61477f565b6157d386614550565b81526060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0840112156158075760008081fd5b61580f6147e9565b925061581c888801614550565b835260408088013561582d8161572c565b848a0152908701359061583f8261487f565b83015280870191909152825260809390930192908401906157a8565b6000806040838503121561586e57600080fd5b61587783614550565b9150615418602084016149e4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610d1e57610d1e615885565b600082615901577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261593b57600080fd5b83018035915067ffffffffffffffff82111561595657600080fd5b6020019150600681901b360382131561205157600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461457457600080fd5b6000604082840312156159db57600080fd5b6159e361477f565b6159ec83614550565b81526159fa6020840161599d565b60208201529392505050565b600060408284031215615a1857600080fd5b615a2061477f565b6159ec836149e4565b60006020808385031215615a3c57600080fd5b823567ffffffffffffffff811115615a5357600080fd5b8301601f81018513615a6457600080fd5b8035615a726148e18261485b565b81815260609182028301840191848201919088841115615a9157600080fd5b938501935b838510156149d85780858a031215615aae5760008081fd5b615ab66147e9565b615abf86614550565b8152615acc87870161599d565b878201526040615add818801614d3b565b9082015283529384019391850191615a96565b81810381811115610d1e57610d1e615885565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112615b3857600080fd5b83018035915067ffffffffffffffff821115615b5357600080fd5b60200191503681900382131561205157600080fd5b80820180821115610d1e57610d1e615885565b7fffffffff0000000000000000000000000000000000000000000000000000000081358181169160048510156150cd5760049490940360031b84901b1690921692915050565b60008085851115615bd157600080fd5b83861115615bde57600080fd5b5050820193919092039150565b600060408284031215615bfd57600080fd5b615c0561477f565b8251815260208301516159fa8161487f565b600060208284031215615c2957600080fd5b5051919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61833603018112615c6457600080fd5b9190910192915050565b60ff8181168382160190811115610d1e57610d1e615885565b600181815b80851115615ce057817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615cc657615cc6615885565b80851615615cd357918102915b93841c9390800290615c8c565b509250929050565b600082615cf757506001610d1e565b81615d0457506000610d1e565b8160018114615d1a5760028114615d2457615d40565b6001915050610d1e565b60ff841115615d3557615d35615885565b50506001821b610d1e565b5060208310610133831016604e8410600b8410161715615d63575081810a610d1e565b615d6d8383615c87565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04821115615d9f57615d9f615885565b029392505050565b6000610bec8383615ce8565b805169ffffffffffffffffffff8116811461457457600080fd5b600080600080600060a08688031215615de557600080fd5b615dee86615db3565b9450602086015193506040860151925060608601519150615e1160808701615db3565b90509295509295909350565b600060208284031215615e2f57600080fd5b8151610bec8161572c565b600060408284031215615e4c57600080fd5b615e5461477f565b615e5d83614550565b8152602083013560208201528091505092915050565b63ffffffff8181168382160190808211156144a2576144a2615885565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000818000a", } var FeeQuoterABI = FeeQuoterMetaData.ABI diff --git a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 95a62aad83b..44cf1653c8c 100644 --- a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -6,7 +6,7 @@ ccip_encoding_utils: ../../../contracts/solc/v0.8.24/ICCIPEncodingUtils/ICCIPEnc ccip_home: ../../../contracts/solc/v0.8.24/CCIPHome/CCIPHome.abi ../../../contracts/solc/v0.8.24/CCIPHome/CCIPHome.bin 865bc25c54cf346e5f519dc3fb625260a12c80983b5ba2dcea63519a7befc660 ccip_reader_tester: ../../../contracts/solc/v0.8.24/CCIPReaderTester/CCIPReaderTester.abi ../../../contracts/solc/v0.8.24/CCIPReaderTester/CCIPReaderTester.bin b368699ae7dbee7c21d049a641642837f18ce2cc8d4ece69509f205de673108e ether_sender_receiver: ../../../contracts/solc/v0.8.24/EtherSenderReceiver/EtherSenderReceiver.abi ../../../contracts/solc/v0.8.24/EtherSenderReceiver/EtherSenderReceiver.bin 09510a3f773f108a3c231e8d202835c845ded862d071ec54c4f89c12d868b8de -fee_quoter: ../../../contracts/solc/v0.8.24/FeeQuoter/FeeQuoter.abi ../../../contracts/solc/v0.8.24/FeeQuoter/FeeQuoter.bin aee49c9246d5903e68b175516b3cdfdec5df23e25d53d604cd382b6bc0bf34f7 +fee_quoter: ../../../contracts/solc/v0.8.24/FeeQuoter/FeeQuoter.abi ../../../contracts/solc/v0.8.24/FeeQuoter/FeeQuoter.bin 95cf64cb4e2f7110469db455218aefea7b8cf1b5deab1a6f07745a4e657fad8c lock_release_token_pool: ../../../contracts/solc/v0.8.24/LockReleaseTokenPool/LockReleaseTokenPool.abi ../../../contracts/solc/v0.8.24/LockReleaseTokenPool/LockReleaseTokenPool.bin 04b40584830294fb603cc2a250af7d831d05a04650a8c2fc9e3af5a78c471be6 maybe_revert_message_receiver: ../../../contracts/solc/v0.8.24/MaybeRevertMessageReceiver/MaybeRevertMessageReceiver.abi ../../../contracts/solc/v0.8.24/MaybeRevertMessageReceiver/MaybeRevertMessageReceiver.bin d73956c26232ebcc4a5444429fa99cbefed960e323be9b5a24925885c2e477d5 message_hasher: ../../../contracts/solc/v0.8.24/MessageHasher/MessageHasher.abi ../../../contracts/solc/v0.8.24/MessageHasher/MessageHasher.bin ec2d3a92348d8e7b8f0d359b62a45157b9d2c750c01fbcf991826c4392f6e218 From 30e3a16c27caf737e4e67a9011d2e917f2cd0669 Mon Sep 17 00:00:00 2001 From: Bolek <1416262+bolekk@users.noreply.github.com> Date: Tue, 17 Dec 2024 08:40:22 -0800 Subject: [PATCH 07/27] [KS-602] Fix for remote exectable client not respecting context (#15721) --- core/capabilities/remote/executable/client.go | 25 +++++++++++++---- .../remote/executable/client_test.go | 28 ++++++++++++++++++- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/core/capabilities/remote/executable/client.go b/core/capabilities/remote/executable/client.go index 776ddb692ad..9f23ff4ce4a 100644 --- a/core/capabilities/remote/executable/client.go +++ b/core/capabilities/remote/executable/client.go @@ -43,6 +43,11 @@ var _ services.Service = &client{} const expiryCheckInterval = 30 * time.Second +var ( + ErrRequestExpired = errors.New("request expired by executable client") + ErrContextDoneBeforeResponseQuorum = errors.New("context done before remote client received a quorum of responses") +) + func NewClient(remoteCapabilityInfo commoncap.CapabilityInfo, localDonInfo commoncap.DON, dispatcher types.Dispatcher, requestTimeout time.Duration, lggr logger.Logger) *client { return &client{ @@ -122,7 +127,7 @@ func (c *client) expireRequests() { for messageID, req := range c.requestIDToCallerRequest { if req.Expired() { - req.Cancel(errors.New("request expired by executable client")) + req.Cancel(ErrRequestExpired) delete(c.requestIDToCallerRequest, messageID) } @@ -164,12 +169,22 @@ func (c *client) Execute(ctx context.Context, capReq commoncap.CapabilityRequest return commoncap.CapabilityResponse{}, fmt.Errorf("failed to send request: %w", err) } - resp := <-req.ResponseChan() - if resp.Err != nil { - return commoncap.CapabilityResponse{}, fmt.Errorf("error executing request: %w", resp.Err) + var respResult []byte + var respErr error + select { + case resp := <-req.ResponseChan(): + respResult = resp.Result + respErr = resp.Err + case <-ctx.Done(): + // NOTE: ClientRequest will not block on sending to ResponseChan() because that channel is buffered (with size 1) + return commoncap.CapabilityResponse{}, errors.Join(ErrContextDoneBeforeResponseQuorum, ctx.Err()) + } + + if respErr != nil { + return commoncap.CapabilityResponse{}, fmt.Errorf("error executing request: %w", respErr) } - capabilityResponse, err := pb.UnmarshalCapabilityResponse(resp.Result) + capabilityResponse, err := pb.UnmarshalCapabilityResponse(respResult) if err != nil { return commoncap.CapabilityResponse{}, fmt.Errorf("failed to unmarshal capability response: %w", err) } diff --git a/core/capabilities/remote/executable/client_test.go b/core/capabilities/remote/executable/client_test.go index f4e6add82b0..db351b75eb3 100644 --- a/core/capabilities/remote/executable/client_test.go +++ b/core/capabilities/remote/executable/client_test.go @@ -147,7 +147,8 @@ func Test_Client_TimesOutIfInsufficientCapabilityPeerResponses(t *testing.T) { ctx := testutils.Context(t) responseTest := func(t *testing.T, response commoncap.CapabilityResponse, responseError error) { - assert.Error(t, responseError) + require.Error(t, responseError) + require.ErrorIs(t, responseError, executable.ErrRequestExpired) } capability := &TestCapability{} @@ -169,6 +170,31 @@ func Test_Client_TimesOutIfInsufficientCapabilityPeerResponses(t *testing.T) { }) } +func Test_Client_ContextCanceledBeforeQuorumReached(t *testing.T) { + ctx, cancel := context.WithCancel(testutils.Context(t)) + + responseTest := func(t *testing.T, response commoncap.CapabilityResponse, responseError error) { + require.Error(t, responseError) + require.ErrorIs(t, responseError, executable.ErrContextDoneBeforeResponseQuorum) + } + + capability := &TestCapability{} + transmissionSchedule, err := values.NewMap(map[string]any{ + "schedule": transmission.Schedule_AllAtOnce, + "deltaStage": "20s", + }) + require.NoError(t, err) + + cancel() + testClient(t, 2, 20*time.Second, 2, 2, + capability, + func(caller commoncap.ExecutableCapability) { + executeInputs, err := values.NewMap(map[string]any{"executeValue1": "aValue1"}) + require.NoError(t, err) + executeMethod(ctx, caller, transmissionSchedule, executeInputs, responseTest, t) + }) +} + func testClient(t *testing.T, numWorkflowPeers int, workflowNodeResponseTimeout time.Duration, numCapabilityPeers int, capabilityDonF uint8, underlying commoncap.ExecutableCapability, method func(caller commoncap.ExecutableCapability)) { From 2a2293c0d7d5517ef898c11481b6fc4c032a00b8 Mon Sep 17 00:00:00 2001 From: Pablo Estrada <139084212+ecPablo@users.noreply.github.com> Date: Tue, 17 Dec 2024 11:53:11 -0600 Subject: [PATCH 08/27] feat: add changeset for set config on all 3 mcms contracts [DPA-1392] (#15684) * feat: add changeset for set config on all 3 mcms contracts * fix: use _test package and change ctx function. * fix: formatting and comments * fix: unit tests set config * fix: check different configs per role. * fix: pass context and add info logs for success --- .../common/changeset/set_config_mcms.go | 209 ++++++++++++ .../common/changeset/set_config_mcms_test.go | 313 ++++++++++++++++++ 2 files changed, 522 insertions(+) create mode 100644 deployment/common/changeset/set_config_mcms.go create mode 100644 deployment/common/changeset/set_config_mcms_test.go diff --git a/deployment/common/changeset/set_config_mcms.go b/deployment/common/changeset/set_config_mcms.go new file mode 100644 index 00000000000..3ba5d2db4b6 --- /dev/null +++ b/deployment/common/changeset/set_config_mcms.go @@ -0,0 +1,209 @@ +package changeset + +import ( + "context" + "errors" + "fmt" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/smartcontractkit/ccip-owner-contracts/pkg/config" + "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" + "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" + "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + chain_selectors "github.com/smartcontractkit/chain-selectors" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + + "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" + commontypes "github.com/smartcontractkit/chainlink/deployment/common/types" +) + +type ConfigPerRole struct { + Proposer config.Config + Canceller config.Config + Bypasser config.Config +} +type TimelockConfig struct { + MinDelay time.Duration // delay for timelock worker to execute the transfers. +} + +type MCMSConfig struct { + ConfigsPerChain map[uint64]ConfigPerRole + ProposalConfig *TimelockConfig +} + +var _ deployment.ChangeSet[MCMSConfig] = SetConfigMCMS + +// Validate checks that the MCMSConfig is valid +func (cfg MCMSConfig) Validate(e deployment.Environment, selectors []uint64) error { + if len(cfg.ConfigsPerChain) == 0 { + return errors.New("no chain configs provided") + } + // configs should have at least one chain + state, err := MaybeLoadMCMSWithTimelockState(e, selectors) + if err != nil { + return err + } + for chainSelector, c := range cfg.ConfigsPerChain { + family, err := chain_selectors.GetSelectorFamily(chainSelector) + if err != nil { + return err + } + if family != chain_selectors.FamilyEVM { + return fmt.Errorf("chain selector: %d is not an ethereum chain", chainSelector) + } + _, ok := e.Chains[chainSelector] + if !ok { + return fmt.Errorf("chain selector: %d not found in environment", chainSelector) + } + _, ok = state[chainSelector] + if !ok { + return fmt.Errorf("chain selector: %d not found for MCMS state", chainSelector) + } + if err := c.Proposer.Validate(); err != nil { + return err + } + if err := c.Canceller.Validate(); err != nil { + return err + } + if err := c.Bypasser.Validate(); err != nil { + return err + } + } + return nil +} + +// setConfigOrTxData executes set config tx or gets the tx data for the MCMS proposal +func setConfigOrTxData(ctx context.Context, lggr logger.Logger, chain deployment.Chain, cfg config.Config, contract *gethwrappers.ManyChainMultiSig, useMCMS bool) (*types.Transaction, error) { + groupQuorums, groupParents, signerAddresses, signerGroups := cfg.ExtractSetConfigInputs() + opts := deployment.SimTransactOpts() + if !useMCMS { + opts = chain.DeployerKey + } + opts.Context = ctx + tx, err := contract.SetConfig(opts, signerAddresses, signerGroups, groupQuorums, groupParents, false) + if err != nil { + return nil, err + } + if !useMCMS { + _, err = deployment.ConfirmIfNoError(chain, tx, err) + if err != nil { + return nil, err + } + lggr.Infow("SetConfigMCMS tx confirmed", "txHash", tx.Hash().Hex()) + } + return tx, nil +} + +type setConfigTxs struct { + proposerTx *types.Transaction + cancellerTx *types.Transaction + bypasserTx *types.Transaction +} + +// setConfigPerRole sets the configuration for each of the MCMS contract roles on the mcmsState. +func setConfigPerRole(ctx context.Context, lggr logger.Logger, chain deployment.Chain, cfg ConfigPerRole, mcmsState *MCMSWithTimelockState, useMCMS bool) (setConfigTxs, error) { + // Proposer set config + proposerTx, err := setConfigOrTxData(ctx, lggr, chain, cfg.Proposer, mcmsState.ProposerMcm, useMCMS) + if err != nil { + return setConfigTxs{}, err + } + // Canceller set config + cancellerTx, err := setConfigOrTxData(ctx, lggr, chain, cfg.Canceller, mcmsState.CancellerMcm, useMCMS) + if err != nil { + return setConfigTxs{}, err + } + // Bypasser set config + bypasserTx, err := setConfigOrTxData(ctx, lggr, chain, cfg.Bypasser, mcmsState.BypasserMcm, useMCMS) + if err != nil { + return setConfigTxs{}, err + } + + return setConfigTxs{ + proposerTx: proposerTx, + cancellerTx: cancellerTx, + bypasserTx: bypasserTx, + }, nil +} + +func addTxsToProposalBatch(setConfigTxsChain setConfigTxs, chainSelector uint64, state MCMSWithTimelockState) timelock.BatchChainOperation { + result := timelock.BatchChainOperation{ + ChainIdentifier: mcms.ChainIdentifier(chainSelector), + Batch: []mcms.Operation{}, + } + result.Batch = append(result.Batch, mcms.Operation{ + To: state.ProposerMcm.Address(), + Data: setConfigTxsChain.proposerTx.Data(), + Value: big.NewInt(0), + ContractType: string(commontypes.ProposerManyChainMultisig), + }) + result.Batch = append(result.Batch, mcms.Operation{ + To: state.CancellerMcm.Address(), + Data: setConfigTxsChain.cancellerTx.Data(), + Value: big.NewInt(0), + ContractType: string(commontypes.CancellerManyChainMultisig), + }) + result.Batch = append(result.Batch, mcms.Operation{ + To: state.BypasserMcm.Address(), + Data: setConfigTxsChain.bypasserTx.Data(), + Value: big.NewInt(0), + ContractType: string(commontypes.BypasserManyChainMultisig), + }) + return result +} + +// SetConfigMCMS sets the configuration of the MCMS contract on the chain identified by the chainSelector. +func SetConfigMCMS(e deployment.Environment, cfg MCMSConfig) (deployment.ChangesetOutput, error) { + selectors := []uint64{} + lggr := e.Logger + ctx := e.GetContext() + for chainSelector := range cfg.ConfigsPerChain { + selectors = append(selectors, chainSelector) + } + useMCMS := cfg.ProposalConfig != nil + err := cfg.Validate(e, selectors) + if err != nil { + return deployment.ChangesetOutput{}, err + } + + batches := []timelock.BatchChainOperation{} + timelocksPerChain := map[uint64]common.Address{} + proposerMcmsPerChain := map[uint64]*gethwrappers.ManyChainMultiSig{} + + mcmsStatePerChain, err := MaybeLoadMCMSWithTimelockState(e, selectors) + if err != nil { + return deployment.ChangesetOutput{}, err + } + + for chainSelector, c := range cfg.ConfigsPerChain { + chain := e.Chains[chainSelector] + state := mcmsStatePerChain[chainSelector] + timelocksPerChain[chainSelector] = state.Timelock.Address() + proposerMcmsPerChain[chainSelector] = state.ProposerMcm + setConfigTxsChain, err := setConfigPerRole(ctx, lggr, chain, c, state, useMCMS) + if err != nil { + return deployment.ChangesetOutput{}, err + } + if useMCMS { + batch := addTxsToProposalBatch(setConfigTxsChain, chainSelector, *state) + batches = append(batches, batch) + } + + } + + if useMCMS { + // Create MCMS with timelock proposal + proposal, err := proposalutils.BuildProposalFromBatches(timelocksPerChain, proposerMcmsPerChain, batches, "Set config proposal", cfg.ProposalConfig.MinDelay) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to build proposal from batch: %w", err) + } + lggr.Infow("SetConfigMCMS proposal created", "proposal", proposal) + return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{*proposal}}, nil + } + + return deployment.ChangesetOutput{}, nil +} diff --git a/deployment/common/changeset/set_config_mcms_test.go b/deployment/common/changeset/set_config_mcms_test.go new file mode 100644 index 00000000000..7220bdd755a --- /dev/null +++ b/deployment/common/changeset/set_config_mcms_test.go @@ -0,0 +1,313 @@ +package changeset_test + +import ( + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/ccip-owner-contracts/pkg/config" + chain_selectors "github.com/smartcontractkit/chain-selectors" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + + commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" + "github.com/smartcontractkit/chainlink/v2/core/logger" + + "github.com/stretchr/testify/require" + "go.uber.org/zap/zapcore" + + "github.com/smartcontractkit/chainlink/deployment" + + "github.com/smartcontractkit/chainlink/deployment/common/types" + "github.com/smartcontractkit/chainlink/deployment/environment/memory" +) + +// setupSetConfigTestEnv deploys all required contracts for the setConfig MCMS contract call. +func setupSetConfigTestEnv(t *testing.T) deployment.Environment { + + lggr := logger.TestLogger(t) + cfg := memory.MemoryEnvironmentConfig{ + Nodes: 1, + Chains: 2, + } + env := memory.NewMemoryEnvironment(t, lggr, zapcore.DebugLevel, cfg) + chainSelector := env.AllChainSelectors()[0] + + config := proposalutils.SingleGroupTimelockConfig(t) + // Deploy MCMS and Timelock + env, err := commonchangeset.ApplyChangesets(t, env, nil, []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployLinkToken), + Config: []uint64{chainSelector}, + }, + { + Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployMCMSWithTimelock), + Config: map[uint64]types.MCMSWithTimelockConfig{ + chainSelector: config, + }, + }, + }) + require.NoError(t, err) + return env +} + +// TestSetConfigMCMSVariants tests the SetConfigMCMS changeset variants. +func TestSetConfigMCMSVariants(t *testing.T) { + + // Add the timelock as a signer to check state changes + for _, tc := range []struct { + name string + changeSets func(mcmsState *commonchangeset.MCMSWithTimelockState, chainSel uint64, cfgProp, cfgCancel, cfgBypass config.Config) []commonchangeset.ChangesetApplication + }{ + { + name: "MCMS disabled", + changeSets: func(mcmsState *commonchangeset.MCMSWithTimelockState, chainSel uint64, cfgProp, cfgCancel, cfgBypass config.Config) []commonchangeset.ChangesetApplication { + + return []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(commonchangeset.SetConfigMCMS), + Config: commonchangeset.MCMSConfig{ + ConfigsPerChain: map[uint64]commonchangeset.ConfigPerRole{ + chainSel: { + Proposer: cfgProp, + Canceller: cfgCancel, + Bypasser: cfgBypass, + }, + }, + }, + }, + } + }, + }, + { + name: "MCMS enabled", + changeSets: func(mcmsState *commonchangeset.MCMSWithTimelockState, chainSel uint64, cfgProp, cfgCancel, cfgBypass config.Config) []commonchangeset.ChangesetApplication { + return []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(commonchangeset.TransferToMCMSWithTimelock), + Config: commonchangeset.TransferToMCMSWithTimelockConfig{ + ContractsByChain: map[uint64][]common.Address{ + chainSel: {mcmsState.ProposerMcm.Address(), mcmsState.BypasserMcm.Address(), mcmsState.CancellerMcm.Address()}, + }, + }, + }, + { + Changeset: commonchangeset.WrapChangeSet(commonchangeset.SetConfigMCMS), + Config: commonchangeset.MCMSConfig{ + ProposalConfig: &commonchangeset.TimelockConfig{ + MinDelay: 0, + }, + ConfigsPerChain: map[uint64]commonchangeset.ConfigPerRole{ + chainSel: { + Proposer: cfgProp, + Canceller: cfgCancel, + Bypasser: cfgBypass, + }, + }, + }, + }, + } + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + ctx := tests.Context(t) + + env := setupSetConfigTestEnv(t) + chainSelector := env.AllChainSelectors()[0] + chain := env.Chains[chainSelector] + addrs, err := env.ExistingAddresses.AddressesForChain(chainSelector) + require.NoError(t, err) + require.Len(t, addrs, 6) + + mcmsState, err := commonchangeset.MaybeLoadMCMSWithTimelockChainState(chain, addrs) + require.NoError(t, err) + timelockAddress := mcmsState.Timelock.Address() + cfgProposer := proposalutils.SingleGroupMCMS(t) + cfgProposer.Signers = append(cfgProposer.Signers, timelockAddress) + cfgProposer.Quorum = 2 // quorum should change to 2 out of 2 signers + timelockMap := map[uint64]*proposalutils.TimelockExecutionContracts{ + chainSelector: { + Timelock: mcmsState.Timelock, + CallProxy: mcmsState.CallProxy, + }, + } + cfgCanceller := proposalutils.SingleGroupMCMS(t) + cfgBypasser := proposalutils.SingleGroupMCMS(t) + cfgBypasser.Signers = append(cfgBypasser.Signers, timelockAddress) + cfgBypasser.Signers = append(cfgBypasser.Signers, mcmsState.ProposerMcm.Address()) + cfgBypasser.Quorum = 3 // quorum should change to 3 out of 3 signers + + // Set config on all 3 MCMS contracts + changesetsToApply := tc.changeSets(mcmsState, chainSelector, cfgProposer, cfgCanceller, cfgBypasser) + _, err = commonchangeset.ApplyChangesets(t, env, timelockMap, changesetsToApply) + require.NoError(t, err) + + // Check new State + expected := cfgProposer.ToRawConfig() + opts := &bind.CallOpts{Context: ctx} + newConf, err := mcmsState.ProposerMcm.GetConfig(opts) + require.NoError(t, err) + require.Equal(t, expected, newConf) + + expected = cfgBypasser.ToRawConfig() + newConf, err = mcmsState.BypasserMcm.GetConfig(opts) + require.NoError(t, err) + require.Equal(t, expected, newConf) + + expected = cfgCanceller.ToRawConfig() + newConf, err = mcmsState.CancellerMcm.GetConfig(opts) + require.NoError(t, err) + require.Equal(t, expected, newConf) + }) + } +} + +func TestValidate(t *testing.T) { + env := setupSetConfigTestEnv(t) + + chainSelector := env.AllChainSelectors()[0] + chain := env.Chains[chainSelector] + addrs, err := env.ExistingAddresses.AddressesForChain(chainSelector) + require.NoError(t, err) + require.Len(t, addrs, 6) + mcmsState, err := commonchangeset.MaybeLoadMCMSWithTimelockChainState(chain, addrs) + require.NoError(t, err) + cfg := proposalutils.SingleGroupMCMS(t) + timelockAddress := mcmsState.Timelock.Address() + // Add the timelock as a signer to check state changes + cfg.Signers = append(cfg.Signers, timelockAddress) + cfg.Quorum = 2 // quorum + + cfgInvalid := proposalutils.SingleGroupMCMS(t) + cfgInvalid.Quorum = 0 + require.NoError(t, err) + tests := []struct { + name string + cfg commonchangeset.MCMSConfig + errorMsg string + }{ + { + name: "valid config", + cfg: commonchangeset.MCMSConfig{ + ProposalConfig: &commonchangeset.TimelockConfig{ + MinDelay: 0, + }, + ConfigsPerChain: map[uint64]commonchangeset.ConfigPerRole{ + chainSelector: { + Proposer: cfg, + Canceller: cfg, + Bypasser: cfg, + }, + }, + }, + }, + { + name: "valid non mcms config", + cfg: commonchangeset.MCMSConfig{ + ConfigsPerChain: map[uint64]commonchangeset.ConfigPerRole{ + chainSelector: { + Proposer: cfg, + Canceller: cfg, + Bypasser: cfg, + }, + }, + }, + }, + { + name: "no chain configurations", + cfg: commonchangeset.MCMSConfig{ + ConfigsPerChain: map[uint64]commonchangeset.ConfigPerRole{}, + }, + errorMsg: "no chain configs provided", + }, + { + name: "non evm chain", + cfg: commonchangeset.MCMSConfig{ + ConfigsPerChain: map[uint64]commonchangeset.ConfigPerRole{ + chain_selectors.APTOS_MAINNET.Selector: { + Proposer: cfg, + Canceller: cfg, + Bypasser: cfg, + }, + }, + }, + errorMsg: "chain selector: 4741433654826277614 is not an ethereum chain", + }, + { + name: "chain selector not found in environment", + cfg: commonchangeset.MCMSConfig{ + ConfigsPerChain: map[uint64]commonchangeset.ConfigPerRole{ + 123: { + Proposer: cfg, + Canceller: cfg, + Bypasser: cfg, + }, + }, + }, + errorMsg: "unknown chain selector 123", + }, + { + name: "invalid proposer config", + cfg: commonchangeset.MCMSConfig{ + ProposalConfig: &commonchangeset.TimelockConfig{ + MinDelay: 0, + }, + ConfigsPerChain: map[uint64]commonchangeset.ConfigPerRole{ + chainSelector: { + Proposer: cfgInvalid, + Canceller: cfg, + Bypasser: cfg, + }, + }, + }, + errorMsg: "invalid MCMS config: Quorum must be greater than 0", + }, + { + name: "invalid canceller config", + cfg: commonchangeset.MCMSConfig{ + ProposalConfig: &commonchangeset.TimelockConfig{ + MinDelay: 0, + }, + ConfigsPerChain: map[uint64]commonchangeset.ConfigPerRole{ + chainSelector: { + Proposer: cfg, + Canceller: cfgInvalid, + Bypasser: cfg, + }, + }, + }, + errorMsg: "invalid MCMS config: Quorum must be greater than 0", + }, + { + name: "invalid bypasser config", + cfg: commonchangeset.MCMSConfig{ + ProposalConfig: &commonchangeset.TimelockConfig{ + MinDelay: 0, + }, + ConfigsPerChain: map[uint64]commonchangeset.ConfigPerRole{ + chainSelector: { + Proposer: cfg, + Canceller: cfg, + Bypasser: cfgInvalid, + }, + }, + }, + errorMsg: "invalid MCMS config: Quorum must be greater than 0", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + selectors := []uint64{chainSelector} + + err := tt.cfg.Validate(env, selectors) + if tt.errorMsg != "" { + require.Error(t, err) + require.Contains(t, err.Error(), tt.errorMsg) + } else { + require.NoError(t, err) + } + }) + } +} From a744ed66541a3bd9b5edb2977ce5e03fa55e6356 Mon Sep 17 00:00:00 2001 From: Erik Burton Date: Tue, 17 Dec 2024 11:49:02 -0800 Subject: [PATCH 09/27] fix: install toolchain version if it exists (#15645) --- .github/actions/setup-go/action.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/actions/setup-go/action.yml b/.github/actions/setup-go/action.yml index ddd4e28e461..e1b15c2b183 100644 --- a/.github/actions/setup-go/action.yml +++ b/.github/actions/setup-go/action.yml @@ -29,10 +29,22 @@ inputs: runs: using: composite steps: + - name: Get Go Version + shell: bash + id: go-version + run: | + version=$(sed -ne '/^toolchain /s/^toolchain go//p' ${{ inputs.go-version-file }}) + if [ -z "$version" ]; then + version=$(sed -ne '/^go /s/^go //p' ${{ inputs.go-version-file }}) + echo "Toolchain version not found in ${{ inputs.go-version-file }}, using go directive instead." + fi + echo "Go Version: $version" + echo "version=$version" >> "$GITHUB_OUTPUT" + - name: Set up Go uses: actions/setup-go@v5.0.2 with: - go-version-file: ${{ inputs.go-version-file }} + go-version: ${{ steps.go-version.outputs.version }} cache: false check-latest: true From 7bcc81e59e9b3ed73143d436fc4525188386dfab Mon Sep 17 00:00:00 2001 From: Sergey Kudasov Date: Wed, 18 Dec 2024 13:15:59 +0100 Subject: [PATCH 10/27] delve support (#15713) * delve support * remove exposed port * move dlv layer for better caching --- GNUmakefile | 3 ++- plugins/chainlink.Dockerfile | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/GNUmakefile b/GNUmakefile index b765c63a3f4..a4377ab2009 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -4,6 +4,7 @@ COMMIT_SHA ?= $(shell git rev-parse HEAD) VERSION = $(shell jq -r '.version' package.json) GO_LDFLAGS := $(shell tools/bin/ldflags) GOFLAGS = -ldflags "$(GO_LDFLAGS)" +GCFLAGS = -gcflags "$(GO_GCFLAGS)" .PHONY: install install: install-chainlink-autoinstall ## Install chainlink and all its dependencies. @@ -38,7 +39,7 @@ docs: ## Install and run pkgsite to view Go docs .PHONY: install-chainlink install-chainlink: operator-ui ## Install the chainlink binary. - go install $(GOFLAGS) . + go install $(GCFLAGS) $(GOFLAGS) . .PHONY: install-chainlink-cover install-chainlink-cover: operator-ui ## Install the chainlink binary with cover flag. diff --git a/plugins/chainlink.Dockerfile b/plugins/chainlink.Dockerfile index a17f5df3898..883aa83c9cf 100644 --- a/plugins/chainlink.Dockerfile +++ b/plugins/chainlink.Dockerfile @@ -12,12 +12,18 @@ RUN go mod download # Env vars needed for chainlink build ARG COMMIT_SHA +# Flags for Go Delve debugger +ARG GO_GCFLAGS + COPY . . RUN apt-get update && apt-get install -y jq +# Install Delve for debugging +RUN go install github.com/go-delve/delve/cmd/dlv@latest + # Build the golang binaries -RUN make install-chainlink +RUN make GO_GCFLAGS="${GO_GCFLAGS}" install-chainlink # Install medianpoc binary RUN make install-medianpoc @@ -52,6 +58,7 @@ WORKDIR /chainlink-starknet/relayer COPY --from=buildgo /chainlink-starknet/relayer . RUN go install ./pkg/chainlink/cmd/chainlink-starknet + # Final image: ubuntu with chainlink binary FROM ubuntu:20.04 @@ -65,6 +72,9 @@ RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \ && apt-get update && apt-get install -y postgresql-client-16 \ && apt-get clean all +# Copy Delve debugger from build stage +COPY --from=buildgo /go/bin/dlv /usr/local/bin/dlv + COPY --from=buildgo /go/bin/chainlink /usr/local/bin/ COPY --from=buildgo /go/bin/chainlink-medianpoc /usr/local/bin/ COPY --from=buildgo /go/bin/chainlink-ocr3-capability /usr/local/bin/ From 935da36c3482bc4f34701ba73c8a2139002f1fc0 Mon Sep 17 00:00:00 2001 From: "Abdelrahman Soliman (Boda)" <2677789+asoliman92@users.noreply.github.com> Date: Wed, 18 Dec 2024 14:58:10 +0200 Subject: [PATCH 11/27] Bump cl-ccip fix commit stale report (#15728) * Increase default transmissionDelay * Fix stale report * deterministic schedules --- 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 47ab9cf536c..fe37eb853a8 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -303,7 +303,7 @@ require ( github.com/shirou/gopsutil/v3 v3.24.3 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix // indirect github.com/smartcontractkit/chain-selectors v1.0.34 // indirect - github.com/smartcontractkit/chainlink-ccip v0.0.0-20241213122413-5e8f65dd6b1b // indirect + github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000 // indirect github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241216163550-fa030d178ba3 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 2840c675dfa..7dfd0fe5097 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1148,8 +1148,8 @@ github.com/smartcontractkit/chain-selectors v1.0.34 h1:MJ17OGu8+jjl426pcKrJkCf3f github.com/smartcontractkit/chain-selectors v1.0.34/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-20241213122413-5e8f65dd6b1b h1:iSQJ6ng4FhEswf8SXunGkaJlVP3E3JlgLB8Oo2f3Ud4= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20241213122413-5e8f65dd6b1b/go.mod h1:F8xQAIW0ymb2BZhqn89sWZLXreJhM5KDVF6Qb4y44N0= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000 h1:6Zzr/R1j6P7bbvcUlt5WUIbItvrrGdGzIsiAzQezcwo= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000/go.mod h1:ncjd6mPZSRlelEqH/2KeLE1pU3UlqzBSn8RYkEoECzY= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805 h1:Pz8jB/6qe10xT10h2S3LFYJrnebNpG5rJ/w16HZGwPQ= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805/go.mod h1:yti7e1+G9hhkYhj+L5sVUULn9Bn3bBL5/AxaNqdJ5YQ= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e h1:PRoeby6ZlTuTkv2f+7tVU4+zboTfRzI+beECynF4JQ0= diff --git a/deployment/go.mod b/deployment/go.mod index e5307c9da60..0f9e66bbb75 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -28,7 +28,7 @@ require ( github.com/sethvargo/go-retry v0.2.4 github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix github.com/smartcontractkit/chain-selectors v1.0.34 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20241213122413-5e8f65dd6b1b + github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000 github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805 github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 diff --git a/deployment/go.sum b/deployment/go.sum index f988f4f37bc..8e4feda0e82 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1415,8 +1415,8 @@ github.com/smartcontractkit/chain-selectors v1.0.34 h1:MJ17OGu8+jjl426pcKrJkCf3f github.com/smartcontractkit/chain-selectors v1.0.34/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-20241213122413-5e8f65dd6b1b h1:iSQJ6ng4FhEswf8SXunGkaJlVP3E3JlgLB8Oo2f3Ud4= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20241213122413-5e8f65dd6b1b/go.mod h1:F8xQAIW0ymb2BZhqn89sWZLXreJhM5KDVF6Qb4y44N0= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000 h1:6Zzr/R1j6P7bbvcUlt5WUIbItvrrGdGzIsiAzQezcwo= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000/go.mod h1:ncjd6mPZSRlelEqH/2KeLE1pU3UlqzBSn8RYkEoECzY= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805 h1:Pz8jB/6qe10xT10h2S3LFYJrnebNpG5rJ/w16HZGwPQ= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805/go.mod h1:yti7e1+G9hhkYhj+L5sVUULn9Bn3bBL5/AxaNqdJ5YQ= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e h1:PRoeby6ZlTuTkv2f+7tVU4+zboTfRzI+beECynF4JQ0= diff --git a/go.mod b/go.mod index 1767da64153..da089c15665 100644 --- a/go.mod +++ b/go.mod @@ -78,7 +78,7 @@ require ( github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chain-selectors v1.0.34 github.com/smartcontractkit/chainlink-automation v0.8.1 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20241213122413-5e8f65dd6b1b + github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000 github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805 github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241216163550-fa030d178ba3 diff --git a/go.sum b/go.sum index 8c7327b4997..28392668c87 100644 --- a/go.sum +++ b/go.sum @@ -1137,8 +1137,8 @@ github.com/smartcontractkit/chain-selectors v1.0.34 h1:MJ17OGu8+jjl426pcKrJkCf3f github.com/smartcontractkit/chain-selectors v1.0.34/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-20241213122413-5e8f65dd6b1b h1:iSQJ6ng4FhEswf8SXunGkaJlVP3E3JlgLB8Oo2f3Ud4= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20241213122413-5e8f65dd6b1b/go.mod h1:F8xQAIW0ymb2BZhqn89sWZLXreJhM5KDVF6Qb4y44N0= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000 h1:6Zzr/R1j6P7bbvcUlt5WUIbItvrrGdGzIsiAzQezcwo= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000/go.mod h1:ncjd6mPZSRlelEqH/2KeLE1pU3UlqzBSn8RYkEoECzY= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805 h1:Pz8jB/6qe10xT10h2S3LFYJrnebNpG5rJ/w16HZGwPQ= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805/go.mod h1:yti7e1+G9hhkYhj+L5sVUULn9Bn3bBL5/AxaNqdJ5YQ= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e h1:PRoeby6ZlTuTkv2f+7tVU4+zboTfRzI+beECynF4JQ0= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index b5da0a24d2d..678598a26c5 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -46,7 +46,7 @@ require ( github.com/slack-go/slack v0.15.0 github.com/smartcontractkit/chain-selectors v1.0.34 github.com/smartcontractkit/chainlink-automation v0.8.1 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20241213122413-5e8f65dd6b1b + github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000 github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805 github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.2 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 71bf4dc9ccb..d846ff5f136 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1436,8 +1436,8 @@ github.com/smartcontractkit/chain-selectors v1.0.34 h1:MJ17OGu8+jjl426pcKrJkCf3f github.com/smartcontractkit/chain-selectors v1.0.34/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-20241213122413-5e8f65dd6b1b h1:iSQJ6ng4FhEswf8SXunGkaJlVP3E3JlgLB8Oo2f3Ud4= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20241213122413-5e8f65dd6b1b/go.mod h1:F8xQAIW0ymb2BZhqn89sWZLXreJhM5KDVF6Qb4y44N0= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000 h1:6Zzr/R1j6P7bbvcUlt5WUIbItvrrGdGzIsiAzQezcwo= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000/go.mod h1:ncjd6mPZSRlelEqH/2KeLE1pU3UlqzBSn8RYkEoECzY= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805 h1:Pz8jB/6qe10xT10h2S3LFYJrnebNpG5rJ/w16HZGwPQ= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805/go.mod h1:yti7e1+G9hhkYhj+L5sVUULn9Bn3bBL5/AxaNqdJ5YQ= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e h1:PRoeby6ZlTuTkv2f+7tVU4+zboTfRzI+beECynF4JQ0= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 96c3bb1dbce..e77f701bf12 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -407,7 +407,7 @@ require ( github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/chain-selectors v1.0.34 // indirect github.com/smartcontractkit/chainlink-automation v0.8.1 // indirect - github.com/smartcontractkit/chainlink-ccip v0.0.0-20241213122413-5e8f65dd6b1b // indirect + github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000 // indirect github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241216163550-fa030d178ba3 // 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 79817cf4311..6c2117a6e7c 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1427,8 +1427,8 @@ github.com/smartcontractkit/chain-selectors v1.0.34 h1:MJ17OGu8+jjl426pcKrJkCf3f github.com/smartcontractkit/chain-selectors v1.0.34/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-20241213122413-5e8f65dd6b1b h1:iSQJ6ng4FhEswf8SXunGkaJlVP3E3JlgLB8Oo2f3Ud4= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20241213122413-5e8f65dd6b1b/go.mod h1:F8xQAIW0ymb2BZhqn89sWZLXreJhM5KDVF6Qb4y44N0= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000 h1:6Zzr/R1j6P7bbvcUlt5WUIbItvrrGdGzIsiAzQezcwo= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000/go.mod h1:ncjd6mPZSRlelEqH/2KeLE1pU3UlqzBSn8RYkEoECzY= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805 h1:Pz8jB/6qe10xT10h2S3LFYJrnebNpG5rJ/w16HZGwPQ= github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805/go.mod h1:yti7e1+G9hhkYhj+L5sVUULn9Bn3bBL5/AxaNqdJ5YQ= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e h1:PRoeby6ZlTuTkv2f+7tVU4+zboTfRzI+beECynF4JQ0= From d1280791a7db204b30ed8bce98bc52b372292cbb Mon Sep 17 00:00:00 2001 From: krehermann <16602512+krehermann@users.noreply.github.com> Date: Wed, 18 Dec 2024 06:05:35 -0700 Subject: [PATCH 12/27] promote decode err to common (#15745) --- deployment/helpers.go | 27 ++++++++++++++++++++++++++- deployment/keystone/deploy.go | 24 +++--------------------- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/deployment/helpers.go b/deployment/helpers.go index dfbbccc2698..34a2584a544 100644 --- a/deployment/helpers.go +++ b/deployment/helpers.go @@ -14,6 +14,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/rpc" "github.com/pkg/errors" chain_selectors "github.com/smartcontractkit/chain-selectors" @@ -87,7 +88,7 @@ func parseError(txError error) (string, error) { return callErr.Data, nil } -func ParseErrorFromABI(errorString string, contractABI string) (string, error) { +func parseErrorFromABI(errorString string, contractABI string) (string, error) { parsedAbi, err := abi.JSON(strings.NewReader(contractABI)) if err != nil { return "", errors.Wrap(err, "error loading ABI") @@ -112,6 +113,30 @@ func ParseErrorFromABI(errorString string, contractABI string) (string, error) { return "", errors.New("error not found in ABI") } +// DecodeErr decodes an error from a contract call using the contract's ABI. +// If the error is not decodable, it returns the original error. +func DecodeErr(encodedABI string, err error) error { + if err == nil { + return nil + } + //revive:disable + var d rpc.DataError + ok := errors.As(err, &d) + if ok { + encErr, ok := d.ErrorData().(string) + if !ok { + return fmt.Errorf("error without error data: %s", d.Error()) + } + errStr, parseErr := parseErrorFromABI(encErr, encodedABI) + if parseErr != nil { + return fmt.Errorf("failed to decode error '%s' with abi: %w", encErr, parseErr) + } + return fmt.Errorf("contract error: %s", errStr) + + } + return fmt.Errorf("cannot decode error with abi: %w", err) +} + // ContractDeploy represents the result of an EVM contract deployment // via an abigen Go binding. It contains all the return values // as they are useful in different ways. diff --git a/deployment/keystone/deploy.go b/deployment/keystone/deploy.go index cb7804d0051..3d415c5d2da 100644 --- a/deployment/keystone/deploy.go +++ b/deployment/keystone/deploy.go @@ -14,7 +14,6 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/rpc" "golang.org/x/exp/maps" "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" @@ -605,27 +604,10 @@ func DefaultCapConfig(capType uint8, nNodes int) *capabilitiespb.CapabilityConfi } } +// DEPRECATED: use deployment.DecodeErr instead +// todo: refactor all keystone deps to use deployment.DecodeErr func DecodeErr(encodedABI string, err error) error { - if err == nil { - return nil - } - - //revive:disable - var d rpc.DataError - ok := errors.As(err, &d) - if ok { - encErr, ok := d.ErrorData().(string) - if !ok { - return fmt.Errorf("error without error data: %s", d.Error()) - } - errStr, parseErr := deployment.ParseErrorFromABI(encErr, encodedABI) - if parseErr != nil { - return fmt.Errorf("failed to decode error '%s' with abi: %w", encErr, parseErr) - } - return fmt.Errorf("contract error: %s", errStr) - - } - return fmt.Errorf("cannot decode error with abi: %w", err) + return deployment.DecodeErr(encodedABI, err) } // register nodes From 676e73a8dd1284afaf68367279a2b308dcd471eb Mon Sep 17 00:00:00 2001 From: krehermann <16602512+krehermann@users.noreply.github.com> Date: Wed, 18 Dec 2024 06:59:33 -0700 Subject: [PATCH 13/27] fix proposal message text (#15750) --- deployment/keystone/changeset/deploy_forwarder.go | 2 +- deployment/keystone/changeset/deploy_ocr3.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deployment/keystone/changeset/deploy_forwarder.go b/deployment/keystone/changeset/deploy_forwarder.go index 1e4066770bd..b4b242b72df 100644 --- a/deployment/keystone/changeset/deploy_forwarder.go +++ b/deployment/keystone/changeset/deploy_forwarder.go @@ -97,7 +97,7 @@ func ConfigureForwardContracts(env deployment.Environment, req ConfigureForwardC timelocksPerChain, proposerMCMSes, []timelock.BatchChainOperation{op}, - "proposal to set update nodes", + "proposal to set forwarder config", req.MCMSConfig.MinDuration, ) if err != nil { diff --git a/deployment/keystone/changeset/deploy_ocr3.go b/deployment/keystone/changeset/deploy_ocr3.go index 4dfed1e292c..057bba4c12d 100644 --- a/deployment/keystone/changeset/deploy_ocr3.go +++ b/deployment/keystone/changeset/deploy_ocr3.go @@ -99,7 +99,7 @@ func ConfigureOCR3Contract(env deployment.Environment, cfg ConfigureOCR3Config) timelocksPerChain, proposerMCMSes, []timelock.BatchChainOperation{*resp.Ops}, - "proposal to set update nodes", + "proposal to set OCR3 config", cfg.MCMSConfig.MinDuration, ) if err != nil { From 86bf8bd29e6fc47a8fb738e2a92daabfca682897 Mon Sep 17 00:00:00 2001 From: Will Winder Date: Wed, 18 Dec 2024 09:14:32 -0500 Subject: [PATCH 14/27] ccip: minimal interface changes to get byte slices into calldata func. (#15747) --- .../ccip/ocrimpls/contract_transmitter.go | 65 ++++++++++++------- .../ocrimpls/contract_transmitter_test.go | 14 ++-- .../capabilities/ccip/oraclecreator/plugin.go | 4 +- 3 files changed, 51 insertions(+), 32 deletions(-) diff --git a/core/capabilities/ccip/ocrimpls/contract_transmitter.go b/core/capabilities/ccip/ocrimpls/contract_transmitter.go index e89acac7baa..a4201188240 100644 --- a/core/capabilities/ccip/ocrimpls/contract_transmitter.go +++ b/core/capabilities/ccip/ocrimpls/contract_transmitter.go @@ -7,6 +7,7 @@ import ( "math/big" "github.com/google/uuid" + "github.com/smartcontractkit/libocr/offchainreporting2/chains/evmutil" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" @@ -16,9 +17,19 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" ) -type ToCalldataFunc func(rawReportCtx [2][32]byte, report []byte, rs, ss [][32]byte, vs [32]byte) any - -func ToCommitCalldata(rawReportCtx [2][32]byte, report []byte, rs, ss [][32]byte, vs [32]byte) any { +type ToCalldataFunc func( + rawReportCtx [2][32]byte, + report ocr3types.ReportWithInfo[[]byte], + rs, ss [][32]byte, + vs [32]byte, +) (any, error) + +func ToCommitCalldata( + rawReportCtx [2][32]byte, + report ocr3types.ReportWithInfo[[]byte], + rs, ss [][32]byte, + vs [32]byte, +) (any, error) { // Note that the name of the struct field is very important, since the encoder used // by the chainwriter uses mapstructure, which will use the struct field name to map // to the argument name in the function call. @@ -36,14 +47,19 @@ func ToCommitCalldata(rawReportCtx [2][32]byte, report []byte, rs, ss [][32]byte RawVs [32]byte }{ ReportContext: rawReportCtx, - Report: report, + Report: report.Report, Rs: rs, Ss: ss, RawVs: vs, - } + }, nil } -func ToExecCalldata(rawReportCtx [2][32]byte, report []byte, _, _ [][32]byte, _ [32]byte) any { +func ToExecCalldata( + rawReportCtx [2][32]byte, + report ocr3types.ReportWithInfo[[]byte], + _, _ [][32]byte, + _ [32]byte, +) (any, error) { // Note that the name of the struct field is very important, since the encoder used // by the chainwriter uses mapstructure, which will use the struct field name to map // to the argument name in the function call. @@ -58,13 +74,13 @@ func ToExecCalldata(rawReportCtx [2][32]byte, report []byte, _, _ [][32]byte, _ Report []byte }{ ReportContext: rawReportCtx, - Report: report, - } + Report: report.Report, + }, nil } -var _ ocr3types.ContractTransmitter[[]byte] = &commitTransmitter[[]byte]{} +var _ ocr3types.ContractTransmitter[[]byte] = &commitTransmitter{} -type commitTransmitter[RI any] struct { +type commitTransmitter struct { cw commontypes.ContractWriter fromAccount ocrtypes.Account contractName string @@ -73,15 +89,15 @@ type commitTransmitter[RI any] struct { toCalldataFn ToCalldataFunc } -func XXXNewContractTransmitterTestsOnly[RI any]( +func XXXNewContractTransmitterTestsOnly( cw commontypes.ContractWriter, fromAccount ocrtypes.Account, contractName string, method string, offrampAddress string, toCalldataFn ToCalldataFunc, -) ocr3types.ContractTransmitter[RI] { - return &commitTransmitter[RI]{ +) ocr3types.ContractTransmitter[[]byte] { + return &commitTransmitter{ cw: cw, fromAccount: fromAccount, contractName: contractName, @@ -91,12 +107,12 @@ func XXXNewContractTransmitterTestsOnly[RI any]( } } -func NewCommitContractTransmitter[RI any]( +func NewCommitContractTransmitter( cw commontypes.ContractWriter, fromAccount ocrtypes.Account, offrampAddress string, -) ocr3types.ContractTransmitter[RI] { - return &commitTransmitter[RI]{ +) ocr3types.ContractTransmitter[[]byte] { + return &commitTransmitter{ cw: cw, fromAccount: fromAccount, contractName: consts.ContractNameOffRamp, @@ -106,12 +122,12 @@ func NewCommitContractTransmitter[RI any]( } } -func NewExecContractTransmitter[RI any]( +func NewExecContractTransmitter( cw commontypes.ContractWriter, fromAccount ocrtypes.Account, offrampAddress string, -) ocr3types.ContractTransmitter[RI] { - return &commitTransmitter[RI]{ +) ocr3types.ContractTransmitter[[]byte] { + return &commitTransmitter{ cw: cw, fromAccount: fromAccount, contractName: consts.ContractNameOffRamp, @@ -122,16 +138,16 @@ func NewExecContractTransmitter[RI any]( } // FromAccount implements ocr3types.ContractTransmitter. -func (c *commitTransmitter[RI]) FromAccount(context.Context) (ocrtypes.Account, error) { +func (c *commitTransmitter) FromAccount(context.Context) (ocrtypes.Account, error) { return c.fromAccount, nil } // Transmit implements ocr3types.ContractTransmitter. -func (c *commitTransmitter[RI]) Transmit( +func (c *commitTransmitter) Transmit( ctx context.Context, configDigest ocrtypes.ConfigDigest, seqNr uint64, - reportWithInfo ocr3types.ReportWithInfo[RI], + reportWithInfo ocr3types.ReportWithInfo[[]byte], sigs []ocrtypes.AttributedOnchainSignature, ) error { var rs [][32]byte @@ -160,7 +176,10 @@ func (c *commitTransmitter[RI]) Transmit( } // chain writer takes in the raw calldata and packs it on its own. - args := c.toCalldataFn(rawReportCtx, reportWithInfo.Report, rs, ss, vs) + args, err := c.toCalldataFn(rawReportCtx, reportWithInfo, rs, ss, vs) + if err != nil { + return fmt.Errorf("failed to generate call data: %w", err) + } // TODO: no meta fields yet, what should we add? // probably whats in the info part of the report? diff --git a/core/capabilities/ccip/ocrimpls/contract_transmitter_test.go b/core/capabilities/ccip/ocrimpls/contract_transmitter_test.go index 16546b26999..5e237ccbee0 100644 --- a/core/capabilities/ccip/ocrimpls/contract_transmitter_test.go +++ b/core/capabilities/ccip/ocrimpls/contract_transmitter_test.go @@ -103,7 +103,7 @@ func testTransmitter( report []byte, ) { ctx := tests.Context(t) - uni := newTestUniverse[[]byte](t, nil) + uni := newTestUniverse(t, nil) c, err := uni.wrapper.LatestConfigDetails(nil, pluginType) require.NoError(t, err, "failed to get latest config details") @@ -199,7 +199,7 @@ type keyringsAndSigners[RI any] struct { signers []common.Address } -func newTestUniverse[RI any](t *testing.T, ks *keyringsAndSigners[RI]) *testUniverse[RI] { +func newTestUniverse(t *testing.T, ks *keyringsAndSigners[[]byte]) *testUniverse[[]byte] { t.Helper() db := pgtest.NewSqlxDB(t) @@ -233,7 +233,7 @@ func newTestUniverse[RI any](t *testing.T, ks *keyringsAndSigners[RI]) *testUniv // create the oracle identities for setConfig // need to create at least 4 identities otherwise setConfig will fail var ( - keyrings []ocr3types.OnchainKeyring[RI] + keyrings []ocr3types.OnchainKeyring[[]byte] signers []common.Address ) if ks != nil { @@ -243,7 +243,7 @@ func newTestUniverse[RI any](t *testing.T, ks *keyringsAndSigners[RI]) *testUniv for i := 0; i < 4; i++ { kb, err2 := ocr2key.New(kschaintype.EVM) require.NoError(t, err2, "failed to create key") - kr := ocrimpls.NewOnchainKeyring[RI](kb, logger.TestLogger(t)) + kr := ocrimpls.NewOnchainKeyring[[]byte](kb, logger.TestLogger(t)) signers = append(signers, common.BytesToAddress(kr.PublicKey())) keyrings = append(keyrings, kr) } @@ -309,7 +309,7 @@ func newTestUniverse[RI any](t *testing.T, ks *keyringsAndSigners[RI]) *testUniv require.NoError(t, chainWriter.Start(testutils.Context(t)), "failed to start chain writer") t.Cleanup(func() { require.NoError(t, chainWriter.Close()) }) - transmitterWithSigs := ocrimpls.XXXNewContractTransmitterTestsOnly[RI]( + transmitterWithSigs := ocrimpls.XXXNewContractTransmitterTestsOnly( chainWriter, ocrtypes.Account(transmitters[0].Hex()), contractName, @@ -317,7 +317,7 @@ func newTestUniverse[RI any](t *testing.T, ks *keyringsAndSigners[RI]) *testUniv ocr3HelperAddr.Hex(), ocrimpls.ToCommitCalldata, ) - transmitterWithoutSigs := ocrimpls.XXXNewContractTransmitterTestsOnly[RI]( + transmitterWithoutSigs := ocrimpls.XXXNewContractTransmitterTestsOnly( chainWriter, ocrtypes.Account(transmitters[0].Hex()), contractName, @@ -326,7 +326,7 @@ func newTestUniverse[RI any](t *testing.T, ks *keyringsAndSigners[RI]) *testUniv ocrimpls.ToExecCalldata, ) - return &testUniverse[RI]{ + return &testUniverse[[]byte]{ simClient: simClient, backend: backend, deployer: owner, diff --git a/core/capabilities/ccip/oraclecreator/plugin.go b/core/capabilities/ccip/oraclecreator/plugin.go index a716d96418a..d4c5596aeaf 100644 --- a/core/capabilities/ccip/oraclecreator/plugin.go +++ b/core/capabilities/ccip/oraclecreator/plugin.go @@ -271,7 +271,7 @@ func (i *pluginOracleCreator) createFactoryAndTransmitter( rmnCrypto, ) factory = promwrapper.NewReportingPluginFactory[[]byte](factory, i.lggr, chainID, "CCIPCommit") - transmitter = ocrimpls.NewCommitContractTransmitter[[]byte](destChainWriter, + transmitter = ocrimpls.NewCommitContractTransmitter(destChainWriter, ocrtypes.Account(destFromAccounts[0]), hexutil.Encode(config.Config.OfframpAddress), // TODO: this works for evm only, how about non-evm? ) @@ -292,7 +292,7 @@ func (i *pluginOracleCreator) createFactoryAndTransmitter( chainWriters, ) factory = promwrapper.NewReportingPluginFactory[[]byte](factory, i.lggr, chainID, "CCIPExec") - transmitter = ocrimpls.NewExecContractTransmitter[[]byte](destChainWriter, + transmitter = ocrimpls.NewExecContractTransmitter(destChainWriter, ocrtypes.Account(destFromAccounts[0]), hexutil.Encode(config.Config.OfframpAddress), // TODO: this works for evm only, how about non-evm? ) From b246e25c3bbc1b9663f3bd1cf844ea56f3b08618 Mon Sep 17 00:00:00 2001 From: Vyzaldy Sanchez Date: Wed, 18 Dec 2024 11:04:15 -0400 Subject: [PATCH 15/27] Add mock for `OffchainClient` from `deployment` (#15580) * Adds mock for `OffchainClient` from `deployment` * Updates mockery files * Runs mockery and all dirs with a `.mockery.yaml` file --- GNUmakefile | 2 +- deployment/.mockery.yaml | 13 + deployment/mocks/offchain_client_mock.go | 1375 ++++++++++++++++++++++ 3 files changed, 1389 insertions(+), 1 deletion(-) create mode 100644 deployment/.mockery.yaml create mode 100644 deployment/mocks/offchain_client_mock.go diff --git a/GNUmakefile b/GNUmakefile index a4377ab2009..470d41c697b 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -98,7 +98,7 @@ abigen: ## Build & install abigen. .PHONY: generate generate: abigen codecgen mockery protoc gomods ## Execute all go:generate commands. gomods -w go generate -x ./... - mockery + find . -type f -name .mockery.yaml -execdir mockery \; ## Execute mockery for all .mockery.yaml files .PHONY: rm-mocked rm-mocked: diff --git a/deployment/.mockery.yaml b/deployment/.mockery.yaml new file mode 100644 index 00000000000..79e4d52104a --- /dev/null +++ b/deployment/.mockery.yaml @@ -0,0 +1,13 @@ +dir: "{{ .InterfaceDir }}/mocks" +mockname: "{{ .InterfaceName }}" +outpkg: mocks +filename: "{{ .InterfaceName | snakecase }}.go" +packages: + github.com/smartcontractkit/chainlink/deployment: + interfaces: + OffchainClient: + config: + mockname: "Mock{{ .InterfaceName }}" + filename: offchain_client_mock.go + inpackage: true + dir: "{{ .InterfaceDir }}/mocks" \ No newline at end of file diff --git a/deployment/mocks/offchain_client_mock.go b/deployment/mocks/offchain_client_mock.go new file mode 100644 index 00000000000..de7a6df3a0d --- /dev/null +++ b/deployment/mocks/offchain_client_mock.go @@ -0,0 +1,1375 @@ +// Code generated by mockery v2.46.3. DO NOT EDIT. + +package deployment + +import ( + context "context" + + csa "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/csa" + grpc "google.golang.org/grpc" + + job "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" + + mock "github.com/stretchr/testify/mock" + + node "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node" +) + +// MockOffchainClient is an autogenerated mock type for the OffchainClient type +type MockOffchainClient struct { + mock.Mock +} + +type MockOffchainClient_Expecter struct { + mock *mock.Mock +} + +func (_m *MockOffchainClient) EXPECT() *MockOffchainClient_Expecter { + return &MockOffchainClient_Expecter{mock: &_m.Mock} +} + +// BatchProposeJob provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) BatchProposeJob(ctx context.Context, in *job.BatchProposeJobRequest, opts ...grpc.CallOption) (*job.BatchProposeJobResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for BatchProposeJob") + } + + var r0 *job.BatchProposeJobResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *job.BatchProposeJobRequest, ...grpc.CallOption) (*job.BatchProposeJobResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *job.BatchProposeJobRequest, ...grpc.CallOption) *job.BatchProposeJobResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*job.BatchProposeJobResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *job.BatchProposeJobRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_BatchProposeJob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BatchProposeJob' +type MockOffchainClient_BatchProposeJob_Call struct { + *mock.Call +} + +// BatchProposeJob is a helper method to define mock.On call +// - ctx context.Context +// - in *job.BatchProposeJobRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) BatchProposeJob(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_BatchProposeJob_Call { + return &MockOffchainClient_BatchProposeJob_Call{Call: _e.mock.On("BatchProposeJob", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_BatchProposeJob_Call) Run(run func(ctx context.Context, in *job.BatchProposeJobRequest, opts ...grpc.CallOption)) *MockOffchainClient_BatchProposeJob_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*job.BatchProposeJobRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_BatchProposeJob_Call) Return(_a0 *job.BatchProposeJobResponse, _a1 error) *MockOffchainClient_BatchProposeJob_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_BatchProposeJob_Call) RunAndReturn(run func(context.Context, *job.BatchProposeJobRequest, ...grpc.CallOption) (*job.BatchProposeJobResponse, error)) *MockOffchainClient_BatchProposeJob_Call { + _c.Call.Return(run) + return _c +} + +// DeleteJob provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) DeleteJob(ctx context.Context, in *job.DeleteJobRequest, opts ...grpc.CallOption) (*job.DeleteJobResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for DeleteJob") + } + + var r0 *job.DeleteJobResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *job.DeleteJobRequest, ...grpc.CallOption) (*job.DeleteJobResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *job.DeleteJobRequest, ...grpc.CallOption) *job.DeleteJobResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*job.DeleteJobResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *job.DeleteJobRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_DeleteJob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteJob' +type MockOffchainClient_DeleteJob_Call struct { + *mock.Call +} + +// DeleteJob is a helper method to define mock.On call +// - ctx context.Context +// - in *job.DeleteJobRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) DeleteJob(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_DeleteJob_Call { + return &MockOffchainClient_DeleteJob_Call{Call: _e.mock.On("DeleteJob", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_DeleteJob_Call) Run(run func(ctx context.Context, in *job.DeleteJobRequest, opts ...grpc.CallOption)) *MockOffchainClient_DeleteJob_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*job.DeleteJobRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_DeleteJob_Call) Return(_a0 *job.DeleteJobResponse, _a1 error) *MockOffchainClient_DeleteJob_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_DeleteJob_Call) RunAndReturn(run func(context.Context, *job.DeleteJobRequest, ...grpc.CallOption) (*job.DeleteJobResponse, error)) *MockOffchainClient_DeleteJob_Call { + _c.Call.Return(run) + return _c +} + +// DisableNode provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) DisableNode(ctx context.Context, in *node.DisableNodeRequest, opts ...grpc.CallOption) (*node.DisableNodeResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for DisableNode") + } + + var r0 *node.DisableNodeResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *node.DisableNodeRequest, ...grpc.CallOption) (*node.DisableNodeResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *node.DisableNodeRequest, ...grpc.CallOption) *node.DisableNodeResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*node.DisableNodeResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *node.DisableNodeRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_DisableNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DisableNode' +type MockOffchainClient_DisableNode_Call struct { + *mock.Call +} + +// DisableNode is a helper method to define mock.On call +// - ctx context.Context +// - in *node.DisableNodeRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) DisableNode(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_DisableNode_Call { + return &MockOffchainClient_DisableNode_Call{Call: _e.mock.On("DisableNode", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_DisableNode_Call) Run(run func(ctx context.Context, in *node.DisableNodeRequest, opts ...grpc.CallOption)) *MockOffchainClient_DisableNode_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*node.DisableNodeRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_DisableNode_Call) Return(_a0 *node.DisableNodeResponse, _a1 error) *MockOffchainClient_DisableNode_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_DisableNode_Call) RunAndReturn(run func(context.Context, *node.DisableNodeRequest, ...grpc.CallOption) (*node.DisableNodeResponse, error)) *MockOffchainClient_DisableNode_Call { + _c.Call.Return(run) + return _c +} + +// EnableNode provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) EnableNode(ctx context.Context, in *node.EnableNodeRequest, opts ...grpc.CallOption) (*node.EnableNodeResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for EnableNode") + } + + var r0 *node.EnableNodeResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *node.EnableNodeRequest, ...grpc.CallOption) (*node.EnableNodeResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *node.EnableNodeRequest, ...grpc.CallOption) *node.EnableNodeResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*node.EnableNodeResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *node.EnableNodeRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_EnableNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EnableNode' +type MockOffchainClient_EnableNode_Call struct { + *mock.Call +} + +// EnableNode is a helper method to define mock.On call +// - ctx context.Context +// - in *node.EnableNodeRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) EnableNode(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_EnableNode_Call { + return &MockOffchainClient_EnableNode_Call{Call: _e.mock.On("EnableNode", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_EnableNode_Call) Run(run func(ctx context.Context, in *node.EnableNodeRequest, opts ...grpc.CallOption)) *MockOffchainClient_EnableNode_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*node.EnableNodeRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_EnableNode_Call) Return(_a0 *node.EnableNodeResponse, _a1 error) *MockOffchainClient_EnableNode_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_EnableNode_Call) RunAndReturn(run func(context.Context, *node.EnableNodeRequest, ...grpc.CallOption) (*node.EnableNodeResponse, error)) *MockOffchainClient_EnableNode_Call { + _c.Call.Return(run) + return _c +} + +// GetJob provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) GetJob(ctx context.Context, in *job.GetJobRequest, opts ...grpc.CallOption) (*job.GetJobResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetJob") + } + + var r0 *job.GetJobResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *job.GetJobRequest, ...grpc.CallOption) (*job.GetJobResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *job.GetJobRequest, ...grpc.CallOption) *job.GetJobResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*job.GetJobResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *job.GetJobRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_GetJob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetJob' +type MockOffchainClient_GetJob_Call struct { + *mock.Call +} + +// GetJob is a helper method to define mock.On call +// - ctx context.Context +// - in *job.GetJobRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) GetJob(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_GetJob_Call { + return &MockOffchainClient_GetJob_Call{Call: _e.mock.On("GetJob", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_GetJob_Call) Run(run func(ctx context.Context, in *job.GetJobRequest, opts ...grpc.CallOption)) *MockOffchainClient_GetJob_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*job.GetJobRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_GetJob_Call) Return(_a0 *job.GetJobResponse, _a1 error) *MockOffchainClient_GetJob_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_GetJob_Call) RunAndReturn(run func(context.Context, *job.GetJobRequest, ...grpc.CallOption) (*job.GetJobResponse, error)) *MockOffchainClient_GetJob_Call { + _c.Call.Return(run) + return _c +} + +// GetKeypair provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) GetKeypair(ctx context.Context, in *csa.GetKeypairRequest, opts ...grpc.CallOption) (*csa.GetKeypairResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetKeypair") + } + + var r0 *csa.GetKeypairResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *csa.GetKeypairRequest, ...grpc.CallOption) (*csa.GetKeypairResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *csa.GetKeypairRequest, ...grpc.CallOption) *csa.GetKeypairResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*csa.GetKeypairResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *csa.GetKeypairRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_GetKeypair_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetKeypair' +type MockOffchainClient_GetKeypair_Call struct { + *mock.Call +} + +// GetKeypair is a helper method to define mock.On call +// - ctx context.Context +// - in *csa.GetKeypairRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) GetKeypair(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_GetKeypair_Call { + return &MockOffchainClient_GetKeypair_Call{Call: _e.mock.On("GetKeypair", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_GetKeypair_Call) Run(run func(ctx context.Context, in *csa.GetKeypairRequest, opts ...grpc.CallOption)) *MockOffchainClient_GetKeypair_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*csa.GetKeypairRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_GetKeypair_Call) Return(_a0 *csa.GetKeypairResponse, _a1 error) *MockOffchainClient_GetKeypair_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_GetKeypair_Call) RunAndReturn(run func(context.Context, *csa.GetKeypairRequest, ...grpc.CallOption) (*csa.GetKeypairResponse, error)) *MockOffchainClient_GetKeypair_Call { + _c.Call.Return(run) + return _c +} + +// GetNode provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) GetNode(ctx context.Context, in *node.GetNodeRequest, opts ...grpc.CallOption) (*node.GetNodeResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetNode") + } + + var r0 *node.GetNodeResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *node.GetNodeRequest, ...grpc.CallOption) (*node.GetNodeResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *node.GetNodeRequest, ...grpc.CallOption) *node.GetNodeResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*node.GetNodeResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *node.GetNodeRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_GetNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetNode' +type MockOffchainClient_GetNode_Call struct { + *mock.Call +} + +// GetNode is a helper method to define mock.On call +// - ctx context.Context +// - in *node.GetNodeRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) GetNode(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_GetNode_Call { + return &MockOffchainClient_GetNode_Call{Call: _e.mock.On("GetNode", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_GetNode_Call) Run(run func(ctx context.Context, in *node.GetNodeRequest, opts ...grpc.CallOption)) *MockOffchainClient_GetNode_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*node.GetNodeRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_GetNode_Call) Return(_a0 *node.GetNodeResponse, _a1 error) *MockOffchainClient_GetNode_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_GetNode_Call) RunAndReturn(run func(context.Context, *node.GetNodeRequest, ...grpc.CallOption) (*node.GetNodeResponse, error)) *MockOffchainClient_GetNode_Call { + _c.Call.Return(run) + return _c +} + +// GetProposal provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) GetProposal(ctx context.Context, in *job.GetProposalRequest, opts ...grpc.CallOption) (*job.GetProposalResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for GetProposal") + } + + var r0 *job.GetProposalResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *job.GetProposalRequest, ...grpc.CallOption) (*job.GetProposalResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *job.GetProposalRequest, ...grpc.CallOption) *job.GetProposalResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*job.GetProposalResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *job.GetProposalRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_GetProposal_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetProposal' +type MockOffchainClient_GetProposal_Call struct { + *mock.Call +} + +// GetProposal is a helper method to define mock.On call +// - ctx context.Context +// - in *job.GetProposalRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) GetProposal(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_GetProposal_Call { + return &MockOffchainClient_GetProposal_Call{Call: _e.mock.On("GetProposal", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_GetProposal_Call) Run(run func(ctx context.Context, in *job.GetProposalRequest, opts ...grpc.CallOption)) *MockOffchainClient_GetProposal_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*job.GetProposalRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_GetProposal_Call) Return(_a0 *job.GetProposalResponse, _a1 error) *MockOffchainClient_GetProposal_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_GetProposal_Call) RunAndReturn(run func(context.Context, *job.GetProposalRequest, ...grpc.CallOption) (*job.GetProposalResponse, error)) *MockOffchainClient_GetProposal_Call { + _c.Call.Return(run) + return _c +} + +// ListJobs provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) ListJobs(ctx context.Context, in *job.ListJobsRequest, opts ...grpc.CallOption) (*job.ListJobsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListJobs") + } + + var r0 *job.ListJobsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *job.ListJobsRequest, ...grpc.CallOption) (*job.ListJobsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *job.ListJobsRequest, ...grpc.CallOption) *job.ListJobsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*job.ListJobsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *job.ListJobsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_ListJobs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListJobs' +type MockOffchainClient_ListJobs_Call struct { + *mock.Call +} + +// ListJobs is a helper method to define mock.On call +// - ctx context.Context +// - in *job.ListJobsRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) ListJobs(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_ListJobs_Call { + return &MockOffchainClient_ListJobs_Call{Call: _e.mock.On("ListJobs", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_ListJobs_Call) Run(run func(ctx context.Context, in *job.ListJobsRequest, opts ...grpc.CallOption)) *MockOffchainClient_ListJobs_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*job.ListJobsRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_ListJobs_Call) Return(_a0 *job.ListJobsResponse, _a1 error) *MockOffchainClient_ListJobs_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_ListJobs_Call) RunAndReturn(run func(context.Context, *job.ListJobsRequest, ...grpc.CallOption) (*job.ListJobsResponse, error)) *MockOffchainClient_ListJobs_Call { + _c.Call.Return(run) + return _c +} + +// ListKeypairs provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) ListKeypairs(ctx context.Context, in *csa.ListKeypairsRequest, opts ...grpc.CallOption) (*csa.ListKeypairsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListKeypairs") + } + + var r0 *csa.ListKeypairsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *csa.ListKeypairsRequest, ...grpc.CallOption) (*csa.ListKeypairsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *csa.ListKeypairsRequest, ...grpc.CallOption) *csa.ListKeypairsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*csa.ListKeypairsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *csa.ListKeypairsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_ListKeypairs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListKeypairs' +type MockOffchainClient_ListKeypairs_Call struct { + *mock.Call +} + +// ListKeypairs is a helper method to define mock.On call +// - ctx context.Context +// - in *csa.ListKeypairsRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) ListKeypairs(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_ListKeypairs_Call { + return &MockOffchainClient_ListKeypairs_Call{Call: _e.mock.On("ListKeypairs", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_ListKeypairs_Call) Run(run func(ctx context.Context, in *csa.ListKeypairsRequest, opts ...grpc.CallOption)) *MockOffchainClient_ListKeypairs_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*csa.ListKeypairsRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_ListKeypairs_Call) Return(_a0 *csa.ListKeypairsResponse, _a1 error) *MockOffchainClient_ListKeypairs_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_ListKeypairs_Call) RunAndReturn(run func(context.Context, *csa.ListKeypairsRequest, ...grpc.CallOption) (*csa.ListKeypairsResponse, error)) *MockOffchainClient_ListKeypairs_Call { + _c.Call.Return(run) + return _c +} + +// ListNodeChainConfigs provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) ListNodeChainConfigs(ctx context.Context, in *node.ListNodeChainConfigsRequest, opts ...grpc.CallOption) (*node.ListNodeChainConfigsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListNodeChainConfigs") + } + + var r0 *node.ListNodeChainConfigsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *node.ListNodeChainConfigsRequest, ...grpc.CallOption) (*node.ListNodeChainConfigsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *node.ListNodeChainConfigsRequest, ...grpc.CallOption) *node.ListNodeChainConfigsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*node.ListNodeChainConfigsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *node.ListNodeChainConfigsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_ListNodeChainConfigs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListNodeChainConfigs' +type MockOffchainClient_ListNodeChainConfigs_Call struct { + *mock.Call +} + +// ListNodeChainConfigs is a helper method to define mock.On call +// - ctx context.Context +// - in *node.ListNodeChainConfigsRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) ListNodeChainConfigs(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_ListNodeChainConfigs_Call { + return &MockOffchainClient_ListNodeChainConfigs_Call{Call: _e.mock.On("ListNodeChainConfigs", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_ListNodeChainConfigs_Call) Run(run func(ctx context.Context, in *node.ListNodeChainConfigsRequest, opts ...grpc.CallOption)) *MockOffchainClient_ListNodeChainConfigs_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*node.ListNodeChainConfigsRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_ListNodeChainConfigs_Call) Return(_a0 *node.ListNodeChainConfigsResponse, _a1 error) *MockOffchainClient_ListNodeChainConfigs_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_ListNodeChainConfigs_Call) RunAndReturn(run func(context.Context, *node.ListNodeChainConfigsRequest, ...grpc.CallOption) (*node.ListNodeChainConfigsResponse, error)) *MockOffchainClient_ListNodeChainConfigs_Call { + _c.Call.Return(run) + return _c +} + +// ListNodes provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) ListNodes(ctx context.Context, in *node.ListNodesRequest, opts ...grpc.CallOption) (*node.ListNodesResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListNodes") + } + + var r0 *node.ListNodesResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *node.ListNodesRequest, ...grpc.CallOption) (*node.ListNodesResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *node.ListNodesRequest, ...grpc.CallOption) *node.ListNodesResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*node.ListNodesResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *node.ListNodesRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_ListNodes_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListNodes' +type MockOffchainClient_ListNodes_Call struct { + *mock.Call +} + +// ListNodes is a helper method to define mock.On call +// - ctx context.Context +// - in *node.ListNodesRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) ListNodes(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_ListNodes_Call { + return &MockOffchainClient_ListNodes_Call{Call: _e.mock.On("ListNodes", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_ListNodes_Call) Run(run func(ctx context.Context, in *node.ListNodesRequest, opts ...grpc.CallOption)) *MockOffchainClient_ListNodes_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*node.ListNodesRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_ListNodes_Call) Return(_a0 *node.ListNodesResponse, _a1 error) *MockOffchainClient_ListNodes_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_ListNodes_Call) RunAndReturn(run func(context.Context, *node.ListNodesRequest, ...grpc.CallOption) (*node.ListNodesResponse, error)) *MockOffchainClient_ListNodes_Call { + _c.Call.Return(run) + return _c +} + +// ListProposals provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) ListProposals(ctx context.Context, in *job.ListProposalsRequest, opts ...grpc.CallOption) (*job.ListProposalsResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ListProposals") + } + + var r0 *job.ListProposalsResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *job.ListProposalsRequest, ...grpc.CallOption) (*job.ListProposalsResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *job.ListProposalsRequest, ...grpc.CallOption) *job.ListProposalsResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*job.ListProposalsResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *job.ListProposalsRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_ListProposals_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListProposals' +type MockOffchainClient_ListProposals_Call struct { + *mock.Call +} + +// ListProposals is a helper method to define mock.On call +// - ctx context.Context +// - in *job.ListProposalsRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) ListProposals(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_ListProposals_Call { + return &MockOffchainClient_ListProposals_Call{Call: _e.mock.On("ListProposals", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_ListProposals_Call) Run(run func(ctx context.Context, in *job.ListProposalsRequest, opts ...grpc.CallOption)) *MockOffchainClient_ListProposals_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*job.ListProposalsRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_ListProposals_Call) Return(_a0 *job.ListProposalsResponse, _a1 error) *MockOffchainClient_ListProposals_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_ListProposals_Call) RunAndReturn(run func(context.Context, *job.ListProposalsRequest, ...grpc.CallOption) (*job.ListProposalsResponse, error)) *MockOffchainClient_ListProposals_Call { + _c.Call.Return(run) + return _c +} + +// ProposeJob provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) ProposeJob(ctx context.Context, in *job.ProposeJobRequest, opts ...grpc.CallOption) (*job.ProposeJobResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for ProposeJob") + } + + var r0 *job.ProposeJobResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *job.ProposeJobRequest, ...grpc.CallOption) (*job.ProposeJobResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *job.ProposeJobRequest, ...grpc.CallOption) *job.ProposeJobResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*job.ProposeJobResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *job.ProposeJobRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_ProposeJob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ProposeJob' +type MockOffchainClient_ProposeJob_Call struct { + *mock.Call +} + +// ProposeJob is a helper method to define mock.On call +// - ctx context.Context +// - in *job.ProposeJobRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) ProposeJob(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_ProposeJob_Call { + return &MockOffchainClient_ProposeJob_Call{Call: _e.mock.On("ProposeJob", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_ProposeJob_Call) Run(run func(ctx context.Context, in *job.ProposeJobRequest, opts ...grpc.CallOption)) *MockOffchainClient_ProposeJob_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*job.ProposeJobRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_ProposeJob_Call) Return(_a0 *job.ProposeJobResponse, _a1 error) *MockOffchainClient_ProposeJob_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_ProposeJob_Call) RunAndReturn(run func(context.Context, *job.ProposeJobRequest, ...grpc.CallOption) (*job.ProposeJobResponse, error)) *MockOffchainClient_ProposeJob_Call { + _c.Call.Return(run) + return _c +} + +// RegisterNode provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) RegisterNode(ctx context.Context, in *node.RegisterNodeRequest, opts ...grpc.CallOption) (*node.RegisterNodeResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for RegisterNode") + } + + var r0 *node.RegisterNodeResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *node.RegisterNodeRequest, ...grpc.CallOption) (*node.RegisterNodeResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *node.RegisterNodeRequest, ...grpc.CallOption) *node.RegisterNodeResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*node.RegisterNodeResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *node.RegisterNodeRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_RegisterNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RegisterNode' +type MockOffchainClient_RegisterNode_Call struct { + *mock.Call +} + +// RegisterNode is a helper method to define mock.On call +// - ctx context.Context +// - in *node.RegisterNodeRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) RegisterNode(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_RegisterNode_Call { + return &MockOffchainClient_RegisterNode_Call{Call: _e.mock.On("RegisterNode", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_RegisterNode_Call) Run(run func(ctx context.Context, in *node.RegisterNodeRequest, opts ...grpc.CallOption)) *MockOffchainClient_RegisterNode_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*node.RegisterNodeRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_RegisterNode_Call) Return(_a0 *node.RegisterNodeResponse, _a1 error) *MockOffchainClient_RegisterNode_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_RegisterNode_Call) RunAndReturn(run func(context.Context, *node.RegisterNodeRequest, ...grpc.CallOption) (*node.RegisterNodeResponse, error)) *MockOffchainClient_RegisterNode_Call { + _c.Call.Return(run) + return _c +} + +// RevokeJob provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) RevokeJob(ctx context.Context, in *job.RevokeJobRequest, opts ...grpc.CallOption) (*job.RevokeJobResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for RevokeJob") + } + + var r0 *job.RevokeJobResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *job.RevokeJobRequest, ...grpc.CallOption) (*job.RevokeJobResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *job.RevokeJobRequest, ...grpc.CallOption) *job.RevokeJobResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*job.RevokeJobResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *job.RevokeJobRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_RevokeJob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RevokeJob' +type MockOffchainClient_RevokeJob_Call struct { + *mock.Call +} + +// RevokeJob is a helper method to define mock.On call +// - ctx context.Context +// - in *job.RevokeJobRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) RevokeJob(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_RevokeJob_Call { + return &MockOffchainClient_RevokeJob_Call{Call: _e.mock.On("RevokeJob", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_RevokeJob_Call) Run(run func(ctx context.Context, in *job.RevokeJobRequest, opts ...grpc.CallOption)) *MockOffchainClient_RevokeJob_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*job.RevokeJobRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_RevokeJob_Call) Return(_a0 *job.RevokeJobResponse, _a1 error) *MockOffchainClient_RevokeJob_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_RevokeJob_Call) RunAndReturn(run func(context.Context, *job.RevokeJobRequest, ...grpc.CallOption) (*job.RevokeJobResponse, error)) *MockOffchainClient_RevokeJob_Call { + _c.Call.Return(run) + return _c +} + +// UpdateJob provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) UpdateJob(ctx context.Context, in *job.UpdateJobRequest, opts ...grpc.CallOption) (*job.UpdateJobResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for UpdateJob") + } + + var r0 *job.UpdateJobResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *job.UpdateJobRequest, ...grpc.CallOption) (*job.UpdateJobResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *job.UpdateJobRequest, ...grpc.CallOption) *job.UpdateJobResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*job.UpdateJobResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *job.UpdateJobRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_UpdateJob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateJob' +type MockOffchainClient_UpdateJob_Call struct { + *mock.Call +} + +// UpdateJob is a helper method to define mock.On call +// - ctx context.Context +// - in *job.UpdateJobRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) UpdateJob(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_UpdateJob_Call { + return &MockOffchainClient_UpdateJob_Call{Call: _e.mock.On("UpdateJob", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_UpdateJob_Call) Run(run func(ctx context.Context, in *job.UpdateJobRequest, opts ...grpc.CallOption)) *MockOffchainClient_UpdateJob_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*job.UpdateJobRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_UpdateJob_Call) Return(_a0 *job.UpdateJobResponse, _a1 error) *MockOffchainClient_UpdateJob_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_UpdateJob_Call) RunAndReturn(run func(context.Context, *job.UpdateJobRequest, ...grpc.CallOption) (*job.UpdateJobResponse, error)) *MockOffchainClient_UpdateJob_Call { + _c.Call.Return(run) + return _c +} + +// UpdateNode provides a mock function with given fields: ctx, in, opts +func (_m *MockOffchainClient) UpdateNode(ctx context.Context, in *node.UpdateNodeRequest, opts ...grpc.CallOption) (*node.UpdateNodeResponse, error) { + _va := make([]interface{}, len(opts)) + for _i := range opts { + _va[_i] = opts[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx, in) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for UpdateNode") + } + + var r0 *node.UpdateNodeResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *node.UpdateNodeRequest, ...grpc.CallOption) (*node.UpdateNodeResponse, error)); ok { + return rf(ctx, in, opts...) + } + if rf, ok := ret.Get(0).(func(context.Context, *node.UpdateNodeRequest, ...grpc.CallOption) *node.UpdateNodeResponse); ok { + r0 = rf(ctx, in, opts...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*node.UpdateNodeResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, *node.UpdateNodeRequest, ...grpc.CallOption) error); ok { + r1 = rf(ctx, in, opts...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockOffchainClient_UpdateNode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateNode' +type MockOffchainClient_UpdateNode_Call struct { + *mock.Call +} + +// UpdateNode is a helper method to define mock.On call +// - ctx context.Context +// - in *node.UpdateNodeRequest +// - opts ...grpc.CallOption +func (_e *MockOffchainClient_Expecter) UpdateNode(ctx interface{}, in interface{}, opts ...interface{}) *MockOffchainClient_UpdateNode_Call { + return &MockOffchainClient_UpdateNode_Call{Call: _e.mock.On("UpdateNode", + append([]interface{}{ctx, in}, opts...)...)} +} + +func (_c *MockOffchainClient_UpdateNode_Call) Run(run func(ctx context.Context, in *node.UpdateNodeRequest, opts ...grpc.CallOption)) *MockOffchainClient_UpdateNode_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]grpc.CallOption, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(grpc.CallOption) + } + } + run(args[0].(context.Context), args[1].(*node.UpdateNodeRequest), variadicArgs...) + }) + return _c +} + +func (_c *MockOffchainClient_UpdateNode_Call) Return(_a0 *node.UpdateNodeResponse, _a1 error) *MockOffchainClient_UpdateNode_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockOffchainClient_UpdateNode_Call) RunAndReturn(run func(context.Context, *node.UpdateNodeRequest, ...grpc.CallOption) (*node.UpdateNodeResponse, error)) *MockOffchainClient_UpdateNode_Call { + _c.Call.Return(run) + return _c +} + +// NewMockOffchainClient creates a new instance of MockOffchainClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockOffchainClient(t interface { + mock.TestingT + Cleanup(func()) +}) *MockOffchainClient { + mock := &MockOffchainClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} From ec35d77281f8df4d3021c7c94124cc32a2ac5f92 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 18 Dec 2024 09:06:40 -0600 Subject: [PATCH 16/27] core/internal/features/ocr2: parallelize subtests; extend timeouts (#14754) --- core/capabilities/compute/compute_test.go | 2 ++ core/internal/cltest/cltest.go | 6 ++++-- core/internal/features/ocr2/features_ocr2_helper.go | 10 +++++++--- core/internal/features/ocr2/features_ocr2_test.go | 9 ++++++--- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/core/capabilities/compute/compute_test.go b/core/capabilities/compute/compute_test.go index 3e5f501fa61..1b1b6e643e8 100644 --- a/core/capabilities/compute/compute_test.go +++ b/core/capabilities/compute/compute_test.go @@ -77,6 +77,7 @@ func setup(t *testing.T, config Config) testHarness { } func TestComputeStartAddsToRegistry(t *testing.T) { + t.Parallel() th := setup(t, defaultConfig) require.NoError(t, th.compute.Start(tests.Context(t))) @@ -109,6 +110,7 @@ func TestComputeExecuteMissingConfig(t *testing.T) { } func TestComputeExecuteMissingBinary(t *testing.T) { + t.Parallel() th := setup(t, defaultConfig) require.NoError(t, th.compute.Start(tests.Context(t))) diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index a55c57cc9a2..b8b34919b6e 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -999,7 +999,7 @@ func WaitForPipeline(t testing.TB, nodeID int, jobID int32, expectedPipelineRuns t.Helper() var pr []pipeline.Run - gomega.NewWithT(t).Eventually(func() bool { + if !gomega.NewWithT(t).Eventually(func() bool { prs, _, err := jo.PipelineRuns(testutils.Context(t), &jobID, 0, 1000) require.NoError(t, err) @@ -1029,7 +1029,9 @@ func WaitForPipeline(t testing.TB, nodeID int, jobID int32, expectedPipelineRuns jobID, len(pr), ), - ) + ) { + t.Fatal() + } return pr } diff --git a/core/internal/features/ocr2/features_ocr2_helper.go b/core/internal/features/ocr2/features_ocr2_helper.go index 9287d0df5b1..76056d7d23d 100644 --- a/core/internal/features/ocr2/features_ocr2_helper.go +++ b/core/internal/features/ocr2/features_ocr2_helper.go @@ -35,6 +35,7 @@ import ( ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/testhelpers" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" @@ -201,6 +202,7 @@ func RunTestIntegrationOCR2(t *testing.T) { } { test := test t.Run(test.name, func(t *testing.T) { + t.Parallel() owner, b, ocrContractAddress, ocrContract := SetupOCR2Contracts(t) lggr := logger.TestLogger(t) @@ -556,7 +558,7 @@ updateInterval = "1m" return } // Want at least 2 runs so we see all the metadata. - pr := cltest.WaitForPipelineComplete(t, ic, jids[ic], len(completedRuns)+2, 7, apps[ic].JobORM(), 2*time.Minute, 5*time.Second) + pr := cltest.WaitForPipelineComplete(t, ic, jids[ic], len(completedRuns)+2, 7, apps[ic].JobORM(), tests.WaitTimeout(t), 5*time.Second) jb, err2 := pr[0].Outputs.MarshalJSON() if !assert.NoError(t, err2) { return @@ -568,11 +570,13 @@ updateInterval = "1m" // Trail #1: 4 oracles reporting 0, 10, 20, 30. Answer should be 20 (results[4/2]). // Trial #2: 4 oracles reporting 0, 20, 40, 60. Answer should be 40 (results[4/2]). - gomega.NewGomegaWithT(t).Eventually(func() string { + if !gomega.NewGomegaWithT(t).Eventually(func() string { answer, err2 := ocrContract.LatestAnswer(nil) require.NoError(t, err2) return answer.String() - }, 1*time.Minute, 200*time.Millisecond).Should(gomega.Equal(strconv.Itoa(2 * retVal))) + }, tests.WaitTimeout(t), 200*time.Millisecond).Should(gomega.Equal(strconv.Itoa(2 * retVal))) { + t.Fatal() + } for _, app := range apps { jobs, _, err2 := app.JobORM().FindJobs(ctx, 0, 1000) diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index 01c269d19e3..a8a8886c50c 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -27,6 +27,7 @@ import ( confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -224,7 +225,7 @@ updateInterval = "1m" go func() { defer wg.Done() // Want at least 2 runs so we see all the metadata. - pr := cltest.WaitForPipelineComplete(t, ic, jids[ic], 2, 7, apps[ic].JobORM(), 2*time.Minute, 5*time.Second) + pr := cltest.WaitForPipelineComplete(t, ic, jids[ic], 2, 7, apps[ic].JobORM(), tests.WaitTimeout(t), 5*time.Second) jb, err := pr[0].Outputs.MarshalJSON() require.NoError(t, err) assert.Equal(t, []byte(fmt.Sprintf("[\"%d\"]", 10*ic)), jb, "pr[0] %+v pr[1] %+v", pr[0], pr[1]) @@ -234,11 +235,13 @@ updateInterval = "1m" wg.Wait() // 4 oracles reporting 0, 10, 20, 30. Answer should be 20 (results[4/2]). - gomega.NewGomegaWithT(t).Eventually(func() string { + if !gomega.NewGomegaWithT(t).Eventually(func() string { answer, err := ocrContract.LatestAnswer(nil) require.NoError(t, err) return answer.String() - }, 1*time.Minute, 200*time.Millisecond).Should(gomega.Equal("20")) + }, tests.WaitTimeout(t), 200*time.Millisecond).Should(gomega.Equal("20")) { + t.Fatal() + } for _, app := range apps { jobs, _, err := app.JobORM().FindJobs(ctx, 0, 1000) From 085b47c4e22bc058fbc8fad50b8a7559e28d3ce6 Mon Sep 17 00:00:00 2001 From: Matthew Pendrey Date: Wed, 18 Dec 2024 15:25:23 +0000 Subject: [PATCH 17/27] CAPPL-372 update workflow registry to use the same chainreader for initialisation and event reading (#15753) * update workflow registry to use the same chainreader for initialisation and event handling * tidy * tidy --- core/services/chainlink/application.go | 5 - .../workflows/syncer/workflow_syncer_test.go | 42 ++++-- .../workflows/syncer/workflow_registry.go | 142 +++++------------- 3 files changed, 63 insertions(+), 126 deletions(-) diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index d8b9777cb5a..4004b86c341 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -307,10 +307,6 @@ func NewApplication(opts ApplicationOpts) (Application, error) { fetcher.Fetch, workflowstore.NewDBStore(opts.DS, lggr, clockwork.NewRealClock()), opts.CapabilitiesRegistry, custmsg.NewLabeler(), clockwork.NewRealClock(), keys[0]) - loader := syncer.NewWorkflowRegistryContractLoader(lggr, cfg.Capabilities().WorkflowRegistry().Address(), func(ctx context.Context, bytes []byte) (syncer.ContractReader, error) { - return relayer.NewContractReader(ctx, bytes) - }, eventHandler) - globalLogger.Debugw("Creating WorkflowRegistrySyncer") wfSyncer := syncer.NewWorkflowRegistry( lggr, @@ -322,7 +318,6 @@ func NewApplication(opts ApplicationOpts) (Application, error) { QueryCount: 100, }, eventHandler, - loader, workflowDonNotifier, ) diff --git a/core/services/relay/evm/capabilities/workflows/syncer/workflow_syncer_test.go b/core/services/relay/evm/capabilities/workflows/syncer/workflow_syncer_test.go index c7c164803cb..6b3f7c7018d 100644 --- a/core/services/relay/evm/capabilities/workflows/syncer/workflow_syncer_test.go +++ b/core/services/relay/evm/capabilities/workflows/syncer/workflow_syncer_test.go @@ -125,9 +125,6 @@ func Test_EventHandlerStateSync(t *testing.T) { } testEventHandler := newTestEvtHandler() - loader := syncer.NewWorkflowRegistryContractLoader(lggr, wfRegistryAddr.Hex(), func(ctx context.Context, bytes []byte) (syncer.ContractReader, error) { - return backendTH.NewContractReader(ctx, t, bytes) - }, testEventHandler) // Create the registry registry := syncer.NewWorkflowRegistry( @@ -140,7 +137,6 @@ func Test_EventHandlerStateSync(t *testing.T) { QueryCount: 20, }, testEventHandler, - loader, &testDonNotifier{ don: capabilities.DON{ ID: donID, @@ -255,9 +251,6 @@ func Test_InitialStateSync(t *testing.T) { } testEventHandler := newTestEvtHandler() - loader := syncer.NewWorkflowRegistryContractLoader(lggr, wfRegistryAddr.Hex(), func(ctx context.Context, bytes []byte) (syncer.ContractReader, error) { - return backendTH.NewContractReader(ctx, t, bytes) - }, testEventHandler) // Create the worker worker := syncer.NewWorkflowRegistry( @@ -270,7 +263,6 @@ func Test_InitialStateSync(t *testing.T) { QueryCount: 20, }, testEventHandler, - loader, &testDonNotifier{ don: capabilities.DON{ ID: donID, @@ -346,8 +338,11 @@ func Test_SecretsWorker(t *testing.T) { require.NoError(t, err) require.Equal(t, contents, giveContents) - handler := syncer.NewEventHandler(lggr, orm, fetcherFn, nil, nil, - emitter, clockwork.NewFakeClock(), workflowkey.Key{}) + handler := &testSecretsWorkEventHandler{ + wrappedHandler: syncer.NewEventHandler(lggr, orm, fetcherFn, nil, nil, + emitter, clockwork.NewFakeClock(), workflowkey.Key{}), + registeredCh: make(chan syncer.Event, 1), + } worker := syncer.NewWorkflowRegistry( lggr, @@ -357,7 +352,6 @@ func Test_SecretsWorker(t *testing.T) { wfRegistryAddr.Hex(), syncer.WorkflowEventPollerConfig{QueryCount: 20}, handler, - &testWorkflowRegistryContractLoader{}, &testDonNotifier{ don: capabilities.DON{ ID: donID, @@ -374,6 +368,9 @@ func Test_SecretsWorker(t *testing.T) { servicetest.Run(t, worker) + // wait for the workflow to be registered + <-handler.registeredCh + // generate a log event requestForceUpdateSecrets(t, backendTH, wfRegistryC, giveSecretsURL) @@ -434,7 +431,6 @@ func Test_RegistrySyncer_WorkflowRegistered_InitiallyPaused(t *testing.T) { wfRegistryAddr.Hex(), syncer.WorkflowEventPollerConfig{QueryCount: 20}, handler, - &testWorkflowRegistryContractLoader{}, &testDonNotifier{ don: capabilities.DON{ ID: donID, @@ -543,7 +539,6 @@ func Test_RegistrySyncer_WorkflowRegistered_InitiallyActivated(t *testing.T) { wfRegistryAddr.Hex(), syncer.WorkflowEventPollerConfig{QueryCount: 20}, handler, - &testWorkflowRegistryContractLoader{}, &testDonNotifier{ don: capabilities.DON{ ID: donID, @@ -708,3 +703,24 @@ func updateWorkflow( th.Backend.Commit() th.Backend.Commit() } + +type evtHandler interface { + Handle(ctx context.Context, event syncer.Event) error +} + +type testSecretsWorkEventHandler struct { + wrappedHandler evtHandler + registeredCh chan syncer.Event +} + +func (m *testSecretsWorkEventHandler) Handle(ctx context.Context, event syncer.Event) error { + switch { + case event.GetEventType() == syncer.ForceUpdateSecretsEvent: + return m.wrappedHandler.Handle(ctx, event) + case event.GetEventType() == syncer.WorkflowRegisteredEvent: + m.registeredCh <- event + return nil + default: + panic(fmt.Sprintf("unexpected event type: %v", event.GetEventType())) + } +} diff --git a/core/services/workflows/syncer/workflow_registry.go b/core/services/workflows/syncer/workflow_registry.go index 4809f3563ca..26c23411d67 100644 --- a/core/services/workflows/syncer/workflow_registry.go +++ b/core/services/workflows/syncer/workflow_registry.go @@ -130,14 +130,11 @@ type workflowRegistry struct { newContractReaderFn newContractReaderFn - eventPollerCfg WorkflowEventPollerConfig - eventTypes []WorkflowRegistryEventType - handler evtHandler - initialWorkflowsStateLoader initialWorkflowsStateLoader + eventPollerCfg WorkflowEventPollerConfig + eventTypes []WorkflowRegistryEventType + handler evtHandler workflowDonNotifier donNotifier - - reader ContractReader } // WithTicker allows external callers to provide a ticker to the workflowRegistry. This is useful @@ -152,12 +149,6 @@ type evtHandler interface { Handle(ctx context.Context, event Event) error } -type initialWorkflowsStateLoader interface { - // LoadWorkflows loads all the workflows for the given donID from the contract. Returns the head of the chain as of the - // point in time at which the load occurred. - LoadWorkflows(ctx context.Context, don capabilities.DON) (*types.Head, error) -} - type donNotifier interface { WaitForDon(ctx context.Context) (capabilities.DON, error) } @@ -172,7 +163,6 @@ func NewWorkflowRegistry( addr string, eventPollerConfig WorkflowEventPollerConfig, handler evtHandler, - initialWorkflowsStateLoader initialWorkflowsStateLoader, workflowDonNotifier donNotifier, opts ...func(*workflowRegistry), ) *workflowRegistry { @@ -184,16 +174,16 @@ func NewWorkflowRegistry( WorkflowRegisteredEvent, WorkflowUpdatedEvent, } + wr := &workflowRegistry{ - lggr: lggr, - newContractReaderFn: newContractReaderFn, - workflowRegistryAddress: addr, - eventPollerCfg: eventPollerConfig, - stopCh: make(services.StopChan), - eventTypes: ets, - handler: handler, - initialWorkflowsStateLoader: initialWorkflowsStateLoader, - workflowDonNotifier: workflowDonNotifier, + lggr: lggr, + newContractReaderFn: newContractReaderFn, + workflowRegistryAddress: addr, + eventPollerCfg: eventPollerConfig, + stopCh: make(services.StopChan), + eventTypes: ets, + handler: handler, + workflowDonNotifier: workflowDonNotifier, } for _, opt := range opts { @@ -220,8 +210,14 @@ func (w *workflowRegistry) Start(_ context.Context) error { return } + reader, err := w.newWorkflowRegistryContractReader(ctx) + if err != nil { + w.lggr.Criticalf("contract reader unavailable : %s", err) + return + } + w.lggr.Debugw("Loading initial workflows for DON", "DON", don.ID) - loadWorkflowsHead, err := w.initialWorkflowsStateLoader.LoadWorkflows(ctx, don) + loadWorkflowsHead, err := w.loadWorkflows(ctx, don, reader) if err != nil { // TODO - this is a temporary fix to handle the case where the chainreader errors because the contract // contains no workflows. To track: https://smartcontract-it.atlassian.net/browse/CAPPL-393 @@ -235,12 +231,6 @@ func (w *workflowRegistry) Start(_ context.Context) error { } } - reader, err := w.getContractReader(ctx) - if err != nil { - w.lggr.Criticalf("contract reader unavailable : %s", err) - return - } - w.readRegistryEvents(ctx, reader, loadWorkflowsHead.Height) }() @@ -359,36 +349,19 @@ func (w *workflowRegistry) getTicker() <-chan time.Time { return w.ticker } -// getContractReader initializes a contract reader if needed, otherwise returns the existing -// reader. -func (w *workflowRegistry) getContractReader(ctx context.Context) (ContractReader, error) { - c := types.BoundContract{ - Name: WorkflowRegistryContractName, - Address: w.workflowRegistryAddress, - } - - if w.reader == nil { - reader, err := getWorkflowRegistryEventReader(ctx, w.newContractReaderFn, c) - if err != nil { - return nil, err - } - - w.reader = reader - } - - return w.reader, nil -} - type sequenceWithEventType struct { Sequence types.Sequence EventType WorkflowRegistryEventType } -func getWorkflowRegistryEventReader( +func (w *workflowRegistry) newWorkflowRegistryContractReader( ctx context.Context, - newReaderFn newContractReaderFn, - bc types.BoundContract, ) (ContractReader, error) { + bc := types.BoundContract{ + Name: WorkflowRegistryContractName, + Address: w.workflowRegistryAddress, + } + contractReaderCfg := evmtypes.ChainReaderConfig{ Contracts: map[string]evmtypes.ChainContractReader{ WorkflowRegistryContractName: { @@ -404,6 +377,9 @@ func getWorkflowRegistryEventReader( }, ContractABI: workflow_registry_wrapper.WorkflowRegistryABI, Configs: map[string]*evmtypes.ChainReaderDefinition{ + GetWorkflowMetadataListByDONMethodName: { + ChainSpecificName: GetWorkflowMetadataListByDONMethodName, + }, string(ForceUpdateSecretsEvent): { ChainSpecificName: string(ForceUpdateSecretsEvent), ReadType: evmtypes.Event, @@ -438,7 +414,7 @@ func getWorkflowRegistryEventReader( return nil, err } - reader, err := newReaderFn(ctx, marshalledCfg) + reader, err := w.newContractReaderFn(ctx, marshalledCfg) if err != nil { return nil, err } @@ -468,59 +444,9 @@ func (r workflowAsEvent) GetData() any { return r.Data } -type workflowRegistryContractLoader struct { - lggr logger.Logger - workflowRegistryAddress string - newContractReaderFn newContractReaderFn - handler evtHandler -} - -func NewWorkflowRegistryContractLoader( - lggr logger.Logger, - workflowRegistryAddress string, - newContractReaderFn newContractReaderFn, - handler evtHandler, -) *workflowRegistryContractLoader { - return &workflowRegistryContractLoader{ - lggr: lggr.Named("WorkflowRegistryContractLoader"), - workflowRegistryAddress: workflowRegistryAddress, - newContractReaderFn: newContractReaderFn, - handler: handler, - } -} - -func (l *workflowRegistryContractLoader) LoadWorkflows(ctx context.Context, don capabilities.DON) (*types.Head, error) { - // Build the ContractReader config - contractReaderCfg := evmtypes.ChainReaderConfig{ - Contracts: map[string]evmtypes.ChainContractReader{ - WorkflowRegistryContractName: { - ContractABI: workflow_registry_wrapper.WorkflowRegistryABI, - Configs: map[string]*evmtypes.ChainReaderDefinition{ - GetWorkflowMetadataListByDONMethodName: { - ChainSpecificName: GetWorkflowMetadataListByDONMethodName, - }, - }, - }, - }, - } - - contractReaderCfgBytes, err := json.Marshal(contractReaderCfg) - if err != nil { - return nil, fmt.Errorf("failed to marshal contract reader config: %w", err) - } - - contractReader, err := l.newContractReaderFn(ctx, contractReaderCfgBytes) - if err != nil { - return nil, fmt.Errorf("failed to create contract reader: %w", err) - } - - err = contractReader.Bind(ctx, []types.BoundContract{{Name: WorkflowRegistryContractName, Address: l.workflowRegistryAddress}}) - if err != nil { - return nil, fmt.Errorf("failed to bind contract reader: %w", err) - } - +func (w *workflowRegistry) loadWorkflows(ctx context.Context, don capabilities.DON, contractReader ContractReader) (*types.Head, error) { contractBinding := types.BoundContract{ - Address: l.workflowRegistryAddress, + Address: w.workflowRegistryAddress, Name: WorkflowRegistryContractName, } @@ -540,7 +466,7 @@ func (l *workflowRegistryContractLoader) LoadWorkflows(ctx context.Context, don return nil, fmt.Errorf("failed to get lastest value with head data %w", err) } - l.lggr.Debugw("Rehydrating existing workflows", "len", len(workflows.WorkflowMetadataList)) + w.lggr.Debugw("Rehydrating existing workflows", "len", len(workflows.WorkflowMetadataList)) for _, workflow := range workflows.WorkflowMetadataList { toRegisteredEvent := WorkflowRegistryWorkflowRegisteredV1{ WorkflowID: workflow.WorkflowID, @@ -552,11 +478,11 @@ func (l *workflowRegistryContractLoader) LoadWorkflows(ctx context.Context, don ConfigURL: workflow.ConfigURL, SecretsURL: workflow.SecretsURL, } - if err = l.handler.Handle(ctx, workflowAsEvent{ + if err = w.handler.Handle(ctx, workflowAsEvent{ Data: toRegisteredEvent, EventType: WorkflowRegisteredEvent, }); err != nil { - l.lggr.Errorf("failed to handle workflow registration: %s", err) + w.lggr.Errorf("failed to handle workflow registration: %s", err) } } From cdaaeaec1fe0eecd2cb427b2b6d895d2e79e2bfb Mon Sep 17 00:00:00 2001 From: chainchad <96362174+chainchad@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:03:57 -0500 Subject: [PATCH 18/27] Attempt to use latest action for crib-deploy-environment (#15683) --- .github/workflows/crib-integration-test.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/crib-integration-test.yml b/.github/workflows/crib-integration-test.yml index 5dd24167ab0..63c383300ec 100644 --- a/.github/workflows/crib-integration-test.yml +++ b/.github/workflows/crib-integration-test.yml @@ -76,16 +76,18 @@ jobs: echo $GITHUB_WORKSPACE - name: Deploy and validate CRIB Environment for Core - uses: smartcontractkit/.github/actions/crib-deploy-environment@d4d9ce3fad044642d8d2f7ae5aca9f8c78b0073a # crib-deploy-environment@2.1.2 + uses: smartcontractkit/.github/actions/crib-deploy-environment@57f99fbea73056c490c766d50ef582a13ec4f3bb # crib-deploy-environment@7.2.0 id: deploy-crib with: github-token: ${{ steps.token.outputs.access-token }} - api-gateway-host: ${{ secrets.AWS_API_GW_HOST_K8S_STAGE }} + aws-ecr-private-registry: ${{ secrets.AWS_ACCOUNT_ID_PROD }} aws-region: ${{ secrets.AWS_REGION }} aws-role-arn: ${{ secrets.AWS_OIDC_CRIB_ROLE_ARN_STAGE }} - ecr-private-registry: ${{ secrets.AWS_ACCOUNT_ID_PROD }} ingress-base-domain: ${{ secrets.INGRESS_BASE_DOMAIN_STAGE }} + k8s-api-endpoint: ${{ secrets.GAP_HOST_K8S_STAGE }} k8s-cluster-name: ${{ secrets.AWS_K8S_CLUSTER_NAME_STAGE }} + chainlink-team: releng + chainlink-product: crib command: "core-dev-simulated-core-ocr1" crib-alert-slack-webhook: ${{ secrets.CRIB_ALERT_SLACK_WEBHOOK }} product-image: ${{ secrets.AWS_SDLC_ECR_HOSTNAME }}/chainlink @@ -94,7 +96,7 @@ jobs: - name: Set up Go uses: ./.github/actions/setup-go with: - go-version-file: 'go.mod' + go-version-file: "go.mod" - name: Run CRIB integration test working-directory: integration-tests/crib env: From 0603fd3c45e835b9b34884fab44ab44e6d22ff0d Mon Sep 17 00:00:00 2001 From: krehermann <16602512+krehermann@users.noreply.github.com> Date: Wed, 18 Dec 2024 10:34:00 -0700 Subject: [PATCH 19/27] Ks/deployment rm clo (#15754) * logging, edge case fixes * delete used CLO code * remove unused test data --- deployment/environment/clo/don_nodeset.go | 67 - .../environment/clo/don_nodeset_test.go | 104 - deployment/environment/clo/models/models.go | 28 - .../environment/clo/models/models_gen.go | 3653 ----------------- .../environment/clo/offchain_client_impl.go | 271 -- .../clo/offchain_client_impl_test.go | 677 --- .../clo/testdata/keystone_nops.json | 3162 -------------- deployment/environment/clo/utils.go | 101 - deployment/environment/clo/utils_test.go | 168 - deployment/keystone/deploy_test.go | 252 -- deployment/keystone/testdata/asset_nodes.json | 978 ----- .../keystone/testdata/chain_writer_nodes.json | 1447 ------- deployment/keystone/testdata/ocr3config.json | 27 - .../keystone/testdata/workflow_nodes.json | 1107 ----- 14 files changed, 12042 deletions(-) delete mode 100644 deployment/environment/clo/don_nodeset.go delete mode 100644 deployment/environment/clo/don_nodeset_test.go delete mode 100644 deployment/environment/clo/models/models.go delete mode 100644 deployment/environment/clo/models/models_gen.go delete mode 100644 deployment/environment/clo/offchain_client_impl.go delete mode 100644 deployment/environment/clo/offchain_client_impl_test.go delete mode 100644 deployment/environment/clo/testdata/keystone_nops.json delete mode 100644 deployment/environment/clo/utils.go delete mode 100644 deployment/environment/clo/utils_test.go delete mode 100644 deployment/keystone/deploy_test.go delete mode 100644 deployment/keystone/testdata/asset_nodes.json delete mode 100644 deployment/keystone/testdata/chain_writer_nodes.json delete mode 100644 deployment/keystone/testdata/ocr3config.json delete mode 100644 deployment/keystone/testdata/workflow_nodes.json diff --git a/deployment/environment/clo/don_nodeset.go b/deployment/environment/clo/don_nodeset.go deleted file mode 100644 index c4cfa212c0b..00000000000 --- a/deployment/environment/clo/don_nodeset.go +++ /dev/null @@ -1,67 +0,0 @@ -package clo - -import ( - "strings" - - "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" -) - -// CapabilityNodeSets groups nodes by a given filter function, resulting in a map of don name to nodes. -func CapabilityNodeSets(nops []*models.NodeOperator, donFilters map[string]FilterFuncT[*models.Node]) map[string][]*models.NodeOperator { - // first drop bootstraps if they exist because they do not serve capabilities - nonBootstrapNops := FilterNopNodes(nops, func(n *models.Node) bool { - for _, chain := range n.ChainConfigs { - if chain.Ocr2Config.IsBootstrap { - return false - } - } - return true - }) - // apply given filters to non-bootstrap nodes - out := make(map[string][]*models.NodeOperator) - for name, f := range donFilters { - out[name] = FilterNopNodes(nonBootstrapNops, f) - } - return out -} - -// FilterNopNodes filters the nodes of each nop by the provided filter function. -// if a nop has no nodes after filtering, it is not included in the output. -func FilterNopNodes(nops []*models.NodeOperator, f FilterFuncT[*models.Node]) []*models.NodeOperator { - var out []*models.NodeOperator - for _, nop := range nops { - var res []*models.Node - for _, n := range nop.Nodes { - node := n - if f(n) { - res = append(res, node) - } - } - if len(res) > 0 { - filterNop := *nop - filterNop.Nodes = res - out = append(out, &filterNop) - } - } - return out -} - -type FilterFuncT[T any] func(n T) bool - -func ProductFilterGenerator(p models.ProductType) FilterFuncT[*models.Node] { - return func(n *models.Node) bool { - for _, prod := range n.SupportedProducts { - if prod == p { - return true - } - } - return false - } -} - -// this could be generalized to a regex filter -func NodeNameFilterGenerator(contains string) FilterFuncT[*models.Node] { - return func(n *models.Node) bool { - return strings.Contains(n.Name, contains) - } -} diff --git a/deployment/environment/clo/don_nodeset_test.go b/deployment/environment/clo/don_nodeset_test.go deleted file mode 100644 index fab9a81690b..00000000000 --- a/deployment/environment/clo/don_nodeset_test.go +++ /dev/null @@ -1,104 +0,0 @@ -package clo_test - -import ( - "encoding/json" - "os" - "path/filepath" - "sort" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/test-go/testify/require" - - "github.com/smartcontractkit/chainlink/deployment/environment/clo" - "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" -) - -// this is hacky, but there is no first class concept of a chain writer node in CLO -// in prod, probably better to make an explicit list of pubkeys if we can't add a category or product type -// sufficient for testing -var ( - writerFilter = func(n *models.Node) bool { - return strings.Contains(n.Name, "Prod Keystone Cap One") && !strings.Contains(n.Name, "Boot") - } - - assetFilter = func(n *models.Node) bool { - return strings.Contains(n.Name, "Prod Keystone Asset") && !strings.Contains(n.Name, "Bootstrap") - } - - wfFilter = func(n *models.Node) bool { - return strings.Contains(n.Name, "Prod Keystone One") && !strings.Contains(n.Name, "Boot") - } -) - -func TestGenerateNopNodesData(t *testing.T) { - t.Skipf("this test is for generating test data only") - // use for generating keystone deployment test data - // `./bin/fmscli --config ~/.fmsclient/prod.yaml login` - // `./bin/fmscli --config ~/.fmsclient/prod.yaml get nodeOperators > /tmp/all-clo-nops.json` - - regenerateFromCLO := false - if regenerateFromCLO { - path := "/tmp/all-clo-nops.json" - f, err := os.ReadFile(path) - require.NoError(t, err) - type cloData struct { - Nops []*models.NodeOperator `json:"nodeOperators"` - } - var d cloData - require.NoError(t, json.Unmarshal(f, &d)) - require.NotEmpty(t, d.Nops) - allNops := d.Nops - sort.Slice(allNops, func(i, j int) bool { - return allNops[i].ID < allNops[j].ID - }) - - ksFilter := func(n *models.Node) bool { - return writerFilter(n) || assetFilter(n) || wfFilter(n) - } - ksNops := clo.FilterNopNodes(allNops, ksFilter) - require.NotEmpty(t, ksNops) - b, err := json.MarshalIndent(ksNops, "", " ") - require.NoError(t, err) - require.NoError(t, os.WriteFile("testdata/keystone_nops.json", b, 0644)) //nolint:gosec - } - keystoneNops := loadTestNops(t, "testdata/keystone_nops.json") - - m := clo.CapabilityNodeSets(keystoneNops, map[string]clo.FilterFuncT[*models.Node]{ - "workflow": wfFilter, - "chainWriter": writerFilter, - "asset": assetFilter, - }) - assert.Len(t, m, 3) - assert.Len(t, m["workflow"], 10) - assert.Len(t, m["chainWriter"], 10) - assert.Len(t, m["asset"], 16) - - // can be used to derive the test data for the keystone deployment - updateTestData := true - if updateTestData { - d := "/tmp" // change this to the path where you want to write the test, "../deployment/keystone/testdata" - b, err := json.MarshalIndent(m["workflow"], "", " ") - require.NoError(t, err) - require.NoError(t, os.WriteFile(filepath.Join(d, "workflow_nodes.json"), b, 0600)) - - b, err = json.MarshalIndent(m["chainWriter"], "", " ") - require.NoError(t, err) - require.NoError(t, os.WriteFile(filepath.Join(d, "chain_writer_nodes.json"), b, 0600)) - b, err = json.MarshalIndent(m["asset"], "", " ") - require.NoError(t, err) - require.NoError(t, os.WriteFile(filepath.Join(d, "asset_nodes.json"), b, 0600)) - } -} - -func loadTestNops(t *testing.T, path string) []*models.NodeOperator { - f, err := os.ReadFile(path) - require.NoError(t, err) - var nodes []*models.NodeOperator - require.NoError(t, json.Unmarshal(f, &nodes)) - sort.Slice(nodes, func(i, j int) bool { - return nodes[i].ID < nodes[j].ID - }) - return nodes -} diff --git a/deployment/environment/clo/models/models.go b/deployment/environment/clo/models/models.go deleted file mode 100644 index 1d33cff84d5..00000000000 --- a/deployment/environment/clo/models/models.go +++ /dev/null @@ -1,28 +0,0 @@ -// TODO: KS-455: Refactor this package to use chainlink-common -// Fork from: https://github.com/smartcontractkit/feeds-manager/tree/develop/api/models -// until it can be refactored in cahinlink-common. - -// Package models provides generated go types that reflect the GraphQL types -// defined in the API schemas. -// -// To maintain compatibility with the default JSON interfaces, any necessary model -// overrides can be defined this package. -package models - -import "go/types" - -// Generic Error model to override existing GQL Error types and allow unmarshaling of GQL Error unions -type Error struct { - Typename string `json:"__typename,omitempty"` - Message string `json:"message,omitempty"` - Path *[]string `json:"path,omitempty"` -} - -func (e *Error) Underlying() types.Type { return e } -func (e *Error) String() string { return "Error" } - -// Unmarshal GQL Time fields into go strings because by default, time.Time results in zero-value -// timestamps being present in the CLI output, e.g. "createdAt": "0001-01-01T00:00:00Z". -// This is because the default JSON interfaces don't recognize it as an empty value for Time.time -// and fail to omit it when using `json:"omitempty"` tags. -type Time string diff --git a/deployment/environment/clo/models/models_gen.go b/deployment/environment/clo/models/models_gen.go deleted file mode 100644 index 8d8f57c3b56..00000000000 --- a/deployment/environment/clo/models/models_gen.go +++ /dev/null @@ -1,3653 +0,0 @@ -// Forked from https://github.com/smartcontractkit/feeds-manager/blob/afc24439ee1dffd3781b53c9419ccd1eb44f4163/api/models/models_gen.go#L1 -// TODO: KS-455: Refactor this package to use chainlink-common -// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. - -package models - -import ( - "fmt" - "io" - "strconv" -) - -type AggregatorConfig interface { - IsAggregatorConfig() -} - -type AggregatorSpecConfig interface { - IsAggregatorSpecConfig() -} - -type JobConfig interface { - IsJobConfig() -} - -type Action struct { - Name string `json:"name,omitempty"` - ActionType ActionType `json:"actionType,omitempty"` - Run *ActionRun `json:"run,omitempty"` - Tasks []*Task `json:"tasks,omitempty"` -} - -type ActionRun struct { - ID string `json:"id,omitempty"` - Network *Network `json:"network,omitempty"` - ActionType ActionType `json:"actionType,omitempty"` - Status ActionRunStatus `json:"status,omitempty"` - Tasks []*Task `json:"tasks,omitempty"` - TaskRuns []*TaskRun `json:"taskRuns,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` -} - -type ActivateBootstrapNodeInput struct { - ID string `json:"id,omitempty"` - ContractType ContractType `json:"contractType,omitempty"` -} - -type ActivateBootstrapNodePayload struct { - Node *Node `json:"node,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type AddAggregatorInput struct { - Name string `json:"name,omitempty"` - Template string `json:"template,omitempty"` - CategoryID string `json:"categoryID,omitempty"` -} - -type AddChainInput struct { - NetworkID string `json:"networkID,omitempty"` - Template string `json:"template,omitempty"` - // The Display String lets a user differentiate multiple CCIP chains on the same network. It is not unique and used for display purposes only. - DisplayName *string `json:"displayName,omitempty"` -} - -type AddChainPayload struct { - Errors []Error `json:"errors,omitempty"` - Chain *CCIPChain `json:"chain,omitempty"` -} - -type AddChainTestContractsInput struct { - ChainID string `json:"chainID,omitempty"` -} - -type AddChainTestContractsPayload struct { - Chain *CCIPChain `json:"chain,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type AddFeedAggregatorInput struct { - FeedID string `json:"feedID,omitempty"` - Aggregator *AddAggregatorInput `json:"aggregator,omitempty"` -} - -type AddFeedAggregatorPayload struct { - Aggregator *Aggregator `json:"aggregator,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type AddFeedInput struct { - Name string `json:"name,omitempty"` - NetworkID string `json:"networkID,omitempty"` - Proxy *AddProxyInput `json:"proxy,omitempty"` - Aggregator *AddAggregatorInput `json:"aggregator,omitempty"` -} - -type AddFeedPayload struct { - Feed *Feed `json:"feed,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type AddLaneInput struct { - ChainAid string `json:"chainAID,omitempty"` - ChainBid string `json:"chainBID,omitempty"` - Template string `json:"template,omitempty"` - // The Display String lets a user differentiate multiple CCIP chains on the same network. It is not unique and used for display purposes only. - DisplayName *string `json:"displayName,omitempty"` -} - -type AddLanePayload struct { - Errors []Error `json:"errors,omitempty"` - Lane *CCIPLane `json:"lane,omitempty"` -} - -type AddLaneUpgradeInput struct { - LaneID string `json:"laneID,omitempty"` - Template string `json:"template,omitempty"` -} - -type AddLaneUpgradePayload struct { - Lane *CCIPLane `json:"lane,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type AddMercuryV03NetworkStackInput struct { - NetworkID string `json:"networkID,omitempty"` - MercuryServerURL string `json:"mercuryServerURL,omitempty"` - MercuryServerPubKey string `json:"mercuryServerPubKey,omitempty"` - ReadAccessController *ReadAccessController `json:"readAccessController,omitempty"` - NativeSurcharge *string `json:"nativeSurcharge,omitempty"` - Servers *string `json:"servers,omitempty"` -} - -type AddMercuryV03NetworkStackPayload struct { - NetworkStack *MercuryV03NetworkStack `json:"networkStack,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type AddProxyInput struct { - AccessControllerAddress *string `json:"accessControllerAddress,omitempty"` -} - -type AddStorageContractInput struct { - NetworkID string `json:"networkID,omitempty"` - Template string `json:"template,omitempty"` - DisplayName *string `json:"displayName,omitempty"` -} - -type AddStorageContractPayload struct { - StorageContract *StorageContract `json:"storageContract,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type AddTokenInput struct { - Template string `json:"template,omitempty"` -} - -type AddTokenPayload struct { - Token *CCIPToken `json:"token,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type AddTokenPoolInput struct { - ID string `json:"id,omitempty"` - Template string `json:"template,omitempty"` -} - -type AddTokenPoolPayload struct { - Errors []Error `json:"errors,omitempty"` - Chain *CCIPChain `json:"chain,omitempty"` -} - -type AddVerificationProviderInput struct { - FeedID string `json:"feedID,omitempty"` - NetworkStackID string `json:"networkStackID,omitempty"` -} - -type AddVerificationProviderPayload struct { - Feed *MercuryV03Feed `json:"feed,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type Aggregator struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - ContractAddress *string `json:"contractAddress,omitempty"` - ContractType ContractType `json:"contractType,omitempty"` - DeploymentStatus DeploymentStatus `json:"deploymentStatus,omitempty"` - OwnerAddress *string `json:"ownerAddress,omitempty"` - OwnerAddressType *ContractOwnerType `json:"ownerAddressType,omitempty"` - PendingOwnerAddress *string `json:"pendingOwnerAddress,omitempty"` - PendingOwnerType *ContractOwnerType `json:"pendingOwnerType,omitempty"` - TransferOwnershipStatus TransferOwnershipStatus `json:"transferOwnershipStatus,omitempty"` - Don *Don `json:"don,omitempty"` - BootstrapMultiaddrs []string `json:"bootstrapMultiaddrs,omitempty"` - SpecConfig AggregatorSpecConfig `json:"specConfig,omitempty"` - Config AggregatorConfig `json:"config,omitempty"` - Feed *Feed `json:"feed,omitempty"` - Network *Network `json:"network,omitempty"` - Category *Category `json:"category,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` -} - -type AggregatorBilling struct { - MaximumGasPrice string `json:"maximumGasPrice,omitempty"` - ReasonableGasPrice string `json:"reasonableGasPrice,omitempty"` - MicroLinkPerEth string `json:"microLinkPerEth,omitempty"` - LinkGweiPerObservation string `json:"linkGweiPerObservation,omitempty"` - LinkGewiPerTransmission string `json:"linkGewiPerTransmission,omitempty"` -} - -type AggregatorConfigOcr1 struct { - Description string `json:"description,omitempty"` - ReasonableGasPrice string `json:"reasonableGasPrice,omitempty"` - MaximumGasPrice string `json:"maximumGasPrice,omitempty"` - MicroLinkPerEth string `json:"microLinkPerEth,omitempty"` - LinkGweiPerObservation string `json:"linkGweiPerObservation,omitempty"` - LinkGweiPerTransmission string `json:"linkGweiPerTransmission,omitempty"` - MinimumAnswer string `json:"minimumAnswer,omitempty"` - MaximumAnswer string `json:"maximumAnswer,omitempty"` - Decimals string `json:"decimals,omitempty"` - DeltaProgress string `json:"deltaProgress,omitempty"` - DeltaResend string `json:"deltaResend,omitempty"` - DeltaRound string `json:"deltaRound,omitempty"` - DeltaGrace string `json:"deltaGrace,omitempty"` - DeltaC string `json:"deltaC,omitempty"` - AlphaPpb string `json:"alphaPPB,omitempty"` - DeltaStage string `json:"deltaStage,omitempty"` - RMax string `json:"rMax,omitempty"` - S []int `json:"s,omitempty"` - F string `json:"f,omitempty"` -} - -func (AggregatorConfigOcr1) IsAggregatorConfig() {} - -type AggregatorConfigOcr2 struct { - MinimumAnswer string `json:"minimumAnswer,omitempty"` - MaximumAnswer string `json:"maximumAnswer,omitempty"` - Description string `json:"description,omitempty"` - Decimals string `json:"decimals,omitempty"` - DeltaGrace string `json:"deltaGrace,omitempty"` - DeltaProgress string `json:"deltaProgress,omitempty"` - DeltaResend string `json:"deltaResend,omitempty"` - DeltaRound string `json:"deltaRound,omitempty"` - DeltaStage string `json:"deltaStage,omitempty"` - F string `json:"f,omitempty"` - MaxDurationObservation string `json:"maxDurationObservation,omitempty"` - MaxDurationQuery string `json:"maxDurationQuery,omitempty"` - MaxDurationReport string `json:"maxDurationReport,omitempty"` - MaxDurationShouldAcceptFinalizedReport string `json:"maxDurationShouldAcceptFinalizedReport,omitempty"` - MaxDurationShouldTransmitAcceptedReport string `json:"maxDurationShouldTransmitAcceptedReport,omitempty"` - RMax string `json:"rMax,omitempty"` - S []int `json:"s,omitempty"` - AlphaAcceptInfinite bool `json:"alphaAcceptInfinite,omitempty"` - AlphaAcceptPpb string `json:"alphaAcceptPPB,omitempty"` - AlphaReportInfinite bool `json:"alphaReportInfinite,omitempty"` - AlphaReportPpb string `json:"alphaReportPPB,omitempty"` - DeltaC string `json:"deltaC,omitempty"` - ObservationPaymentGjuels string `json:"observationPaymentGjuels,omitempty"` - TransmissionPaymentGjuels string `json:"transmissionPaymentGjuels,omitempty"` - MaximumGasPriceGwei *string `json:"maximumGasPriceGwei,omitempty"` - ReasonableGasPriceGwei *string `json:"reasonableGasPriceGwei,omitempty"` - AccountingGas *string `json:"accountingGas,omitempty"` -} - -func (AggregatorConfigOcr2) IsAggregatorConfig() {} - -type AggregatorOnChainConfig struct { - ConfigCount string `json:"configCount,omitempty"` - BlockNumber string `json:"blockNumber,omitempty"` - ConfigDigest []string `json:"configDigest,omitempty"` -} - -type AggregatorOnChainState struct { - Billing *AggregatorBilling `json:"billing,omitempty"` - Config *AggregatorOnChainConfig `json:"config,omitempty"` - OwnerAddress string `json:"ownerAddress,omitempty"` -} - -type AggregatorProxy struct { - ID string `json:"id,omitempty"` - ContractAddress *string `json:"contractAddress,omitempty"` - TransferOwnershipStatus TransferOwnershipStatus `json:"transferOwnershipStatus,omitempty"` - OwnerAddress *string `json:"ownerAddress,omitempty"` - OwnerAddressType *ContractOwnerType `json:"ownerAddressType,omitempty"` - PendingOwnerAddress *string `json:"pendingOwnerAddress,omitempty"` - PendingOwnerType *ContractOwnerType `json:"pendingOwnerType,omitempty"` - Aggregator *Aggregator `json:"aggregator,omitempty"` - AccessControllerAddress *string `json:"accessControllerAddress,omitempty"` - Feed *Feed `json:"feed,omitempty"` - Network *Network `json:"network,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` -} - -type ArchiveChainPayload struct { - Chain *CCIPChain `json:"chain,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type ArchiveContractInput struct { - ChainID string `json:"chainID,omitempty"` - ContractID string `json:"contractID,omitempty"` -} - -type ArchiveContractPayload struct { - Contract *Contract `json:"contract,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type ArchiveFeedPayload struct { - Feed *MercuryV03Feed `json:"feed,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type ArchiveLanePayload struct { - Lane *CCIPLane `json:"lane,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type ArchiveNetworkInput struct { - ID string `json:"id,omitempty"` -} - -type ArchiveNetworkPayload struct { - Network *Network `json:"network,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type ArchiveNetworkStackPayload struct { - NetworkStack *MercuryV03NetworkStack `json:"networkStack,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type AssignNodeToJobInput struct { - JobID string `json:"jobID,omitempty"` - NodeID string `json:"nodeID,omitempty"` -} - -type AssignNodeToJobPayload struct { - Job *Job `json:"job,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type BuildInfo struct { - Version string `json:"version,omitempty"` -} - -type CCIPChain struct { - ID string `json:"id,omitempty"` - Network *Network `json:"network,omitempty"` - Contracts []*Contract `json:"contracts,omitempty"` - WorkflowRuns []*WorkflowRun `json:"workflowRuns,omitempty"` - SupportedTokens []*EVMBridgedToken `json:"supportedTokens,omitempty"` - FeeTokens []string `json:"feeTokens,omitempty"` - WrappedNativeToken string `json:"wrappedNativeToken,omitempty"` - ArchivedAt *Time `json:"archivedAt,omitempty"` - // The Display String lets a user differentiate multiple CCIP chains on the same network. It is not unique and used for display purposes only. - DisplayName *string `json:"displayName,omitempty"` - DeployedTemplate map[string]interface{} `json:"deployedTemplate,omitempty"` - Labels map[string]interface{} `json:"labels,omitempty"` -} - -type CCIPChainBasic struct { - ID string `json:"id,omitempty"` - ChainID string `json:"chainID,omitempty"` - Contracts []*ContractBasic `json:"contracts,omitempty"` -} - -type CCIPChainFilter struct { - IsArchived *bool `json:"isArchived,omitempty"` - Selectors []*CCIPChainSelector `json:"selectors,omitempty"` -} - -type CCIPChainSelector struct { - Key string `json:"key,omitempty"` - Op SelectorOp `json:"op,omitempty"` - Value *string `json:"value,omitempty"` -} - -type CCIPEndpoint struct { - Chain *CCIPChain `json:"chain,omitempty"` - Contracts []*Contract `json:"contracts,omitempty"` -} - -type CCIPEndpointBasic struct { - Chain *CCIPChainBasic `json:"chain,omitempty"` - Contracts []*ContractBasic `json:"contracts,omitempty"` -} - -type CCIPLane struct { - ID string `json:"id,omitempty"` - ChainA *CCIPChain `json:"chainA,omitempty"` - ChainB *CCIPChain `json:"chainB,omitempty"` - LegA *CCIPLaneLeg `json:"legA,omitempty"` - LegB *CCIPLaneLeg `json:"legB,omitempty"` - LegAProvisional *CCIPLaneLeg `json:"legAProvisional,omitempty"` - LegBProvisional *CCIPLaneLeg `json:"legBProvisional,omitempty"` - Dons []*Don `json:"dons,omitempty"` - WorkflowRuns []*WorkflowRun `json:"workflowRuns,omitempty"` - Status CCIPLaneLegStatus `json:"status,omitempty"` - ArchivedAt *Time `json:"archivedAt,omitempty"` - DisplayName *string `json:"displayName,omitempty"` - DeployedTemplate map[string]interface{} `json:"deployedTemplate,omitempty"` - DeployedProvisionalTemplate map[string]interface{} `json:"deployedProvisionalTemplate,omitempty"` -} - -type CCIPLaneChainUpdateInput struct { - ID string `json:"id,omitempty"` -} - -type CCIPLaneLeg struct { - ID string `json:"id,omitempty"` - Tag CCIPLaneLegTag `json:"tag,omitempty"` - Source *CCIPEndpoint `json:"source,omitempty"` - Destination *CCIPEndpoint `json:"destination,omitempty"` - WorkflowRuns []*WorkflowRun `json:"workflowRuns,omitempty"` - Dons []*Don `json:"dons,omitempty"` - Status CCIPLaneLegStatus `json:"status,omitempty"` - ArchivedAt *Time `json:"archivedAt,omitempty"` - SupportedTokens []string `json:"supportedTokens,omitempty"` -} - -type CCIPLaneLegBasic struct { - ID string `json:"id,omitempty"` - Source *CCIPEndpointBasic `json:"source,omitempty"` - Destination *CCIPEndpointBasic `json:"destination,omitempty"` - Dons []*DONBasic `json:"dons,omitempty"` - Status CCIPLaneLegStatus `json:"status,omitempty"` - SupportedTokens []string `json:"supportedTokens,omitempty"` -} - -type CCIPLaneLegsFilter struct { - ContractAddress string `json:"contractAddress,omitempty"` - NetworkNameKey string `json:"networkNameKey,omitempty"` -} - -type CCIPLanesFilter struct { - IsArchived *bool `json:"isArchived,omitempty"` -} - -type CCIPMutations struct { - AddChain *AddChainPayload `json:"addChain,omitempty"` - ImportChain *ImportChainPayload `json:"importChain,omitempty"` - AddChainTestContracts *AddChainTestContractsPayload `json:"addChainTestContracts,omitempty"` - AddTokenPool *AddTokenPoolPayload `json:"addTokenPool,omitempty"` - ImportTokenPool *ImportTokenPoolPayload `json:"importTokenPool,omitempty"` - AddToken *AddTokenPayload `json:"addToken,omitempty"` - DeployContract *DeployContractPayload `json:"deployContract,omitempty"` - DeleteContract *DeleteContractPayload `json:"deleteContract,omitempty"` - ArchiveContract *ArchiveContractPayload `json:"archiveContract,omitempty"` - // Deploys the contracts for a chain - DeployChain *CcipDeployChainPayload `json:"deployChain,omitempty"` - DeployChainTestContracts *CcipDeployChainTestContractsPayload `json:"deployChainTestContracts,omitempty"` - DeployToken *DeployTokenPayload `json:"deployToken,omitempty"` - DeregisterTestToken *DeregisterTestTokenPayload `json:"deregisterTestToken,omitempty"` - AddLane *AddLanePayload `json:"addLane,omitempty"` - ImportLane *ImportLanePayload `json:"importLane,omitempty"` - AddLaneUpgrade *AddLaneUpgradePayload `json:"addLaneUpgrade,omitempty"` - UpdateLane *UpdateLanePayload `json:"updateLane,omitempty"` - ArchiveLane *ArchiveLanePayload `json:"archiveLane,omitempty"` - ArchiveChain *ArchiveChainPayload `json:"archiveChain,omitempty"` - CancelLaneUpgrade *CancelLaneUpgradePayload `json:"cancelLaneUpgrade,omitempty"` - ConfirmLaneUpgrade *ConfirmLaneUpgradePayload `json:"confirmLaneUpgrade,omitempty"` - DeployLaneLeg *CcipDeployLaneLegPayload `json:"deployLaneLeg,omitempty"` - SetAllowListTokenPool *SetAllowListTokenPoolPayload `json:"setAllowListTokenPool,omitempty"` - // SetConfigLaneLeg sets the on chain configuration for the Commit Store and Off Ramp contracts of the lane leg. - // - // The configuration values passed as arguments to the contract call are provided by the most recently inserted - // RDD template. - SetConfigLaneLeg *CcipSetConfigLaneLegPayload `json:"setConfigLaneLeg,omitempty"` - TransferOwnership *TransferOwnershipPayload `json:"transferOwnership,omitempty"` - TransferAdminRole *TransferAdminRolePayload `json:"transferAdminRole,omitempty"` - UpdateChain *UpdateCCIPChainPayload `json:"updateChain,omitempty"` - RemoveLiquidity *RemoveLiquidityPayload `json:"removeLiquidity,omitempty"` - SyncChain *SyncChainPayload `json:"syncChain,omitempty"` - SyncLane *SyncLanePayload `json:"syncLane,omitempty"` - SyncContracts *SyncContractsPayload `json:"syncContracts,omitempty"` -} - -type CCIPQueries struct { - Chains []*CCIPChain `json:"chains,omitempty"` - Lanes []*CCIPLane `json:"lanes,omitempty"` - LaneLegs []*CCIPLaneLegBasic `json:"laneLegs,omitempty"` - Chain *CCIPChain `json:"chain,omitempty"` - Lane *CCIPLane `json:"lane,omitempty"` - Tokens []*CCIPToken `json:"tokens,omitempty"` - Token *CCIPToken `json:"token,omitempty"` -} - -type CCIPToken struct { - ID string `json:"id,omitempty"` - Symbol string `json:"symbol,omitempty"` - TokenPools []*CCIPTokenPool `json:"tokenPools,omitempty"` -} - -type CCIPTokenPool struct { - ID string `json:"id,omitempty"` - Contract *Contract `json:"contract,omitempty"` - Address *string `json:"address,omitempty"` - TokenAddress string `json:"tokenAddress,omitempty"` - TokenSymbol string `json:"tokenSymbol,omitempty"` - Chain *CCIPChain `json:"chain,omitempty"` - WorkflowRuns []*WorkflowRun `json:"workflowRuns,omitempty"` -} - -type CcipDeployChainInput struct { - ChainID string `json:"chainID,omitempty"` -} - -type CcipDeployChainPayload struct { - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type CcipDeployChainTestContractsInput struct { - ChainID string `json:"chainID,omitempty"` -} - -type CcipDeployChainTestContractsPayload struct { - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type CcipDeployLaneLegInput struct { - LegID string `json:"legID,omitempty"` -} - -type CcipDeployLaneLegPayload struct { - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type CcipSetConfigLaneLegInput struct { - LegID string `json:"legID,omitempty"` -} - -type CcipSetConfigLaneLegPayload struct { - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type CSAKeypair struct { - ID string `json:"id,omitempty"` - PublicKey string `json:"publicKey,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` -} - -type CancelLaneUpgradeInput struct { - LaneID string `json:"laneID,omitempty"` -} - -type CancelLaneUpgradePayload struct { - Errors []Error `json:"errors,omitempty"` - Lane *CCIPLane `json:"lane,omitempty"` -} - -type Category struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Color string `json:"color,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` -} - -type ConfirmLaneUpgradeInput struct { - LaneID string `json:"laneID,omitempty"` -} - -type ConfirmLaneUpgradePayload struct { - Errors []Error `json:"errors,omitempty"` - Lane *CCIPLane `json:"lane,omitempty"` -} - -type Contract struct { - ID string `json:"id,omitempty"` - Network *Network `json:"network,omitempty"` - Name string `json:"name,omitempty"` - Version int `json:"version,omitempty"` - Semver *string `json:"semver,omitempty"` - Tag ContractTag `json:"tag,omitempty"` - Address *string `json:"address,omitempty"` - Metadata map[string]interface{} `json:"metadata,omitempty"` - OwnerAddress *string `json:"ownerAddress,omitempty"` - OwnerType ContractOwnerType `json:"ownerType,omitempty"` - PendingOwnerAddress *string `json:"pendingOwnerAddress,omitempty"` - PendingOwnerType *ContractOwnerType `json:"pendingOwnerType,omitempty"` - TransferOwnershipStatus TransferOwnershipStatus `json:"transferOwnershipStatus,omitempty"` - VerificationStatus VerificationStatus `json:"verificationStatus,omitempty"` - SourceCodeHash string `json:"sourceCodeHash,omitempty"` - DeployedAt *Time `json:"deployedAt,omitempty"` - Imported bool `json:"imported,omitempty"` - ArchivedAt *Time `json:"archivedAt,omitempty"` -} - -type ContractBasic struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Version int `json:"version,omitempty"` - Semver *string `json:"semver,omitempty"` - Address *string `json:"address,omitempty"` - Metadata map[string]interface{} `json:"metadata,omitempty"` -} - -type CreateBootstrapJobInput struct { - DonID string `json:"donID,omitempty"` - NodeID string `json:"nodeID,omitempty"` -} - -type CreateBootstrapJobPayload struct { - Job *Job `json:"job,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type CreateCSAKeypairPayload struct { - CsaKeypair *CSAKeypair `json:"csaKeypair,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type CreateCategoryInput struct { - Name string `json:"name,omitempty"` - Color *string `json:"color,omitempty"` -} - -type CreateCategoryPayload struct { - Category *Category `json:"category,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type CreateJobInput struct { - Type JobType `json:"type,omitempty"` - Ocr2PluginType *OCR2PluginType `json:"ocr2PluginType,omitempty"` - Config *JobConfigInput `json:"config,omitempty"` - DonID string `json:"donID,omitempty"` - NodeOperatorID string `json:"nodeOperatorID,omitempty"` -} - -type CreateJobPayload struct { - Job *Job `json:"job,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type CreateMercuryNetworkStackInput struct { - NetworkID string `json:"networkID,omitempty"` - VerifierAddress string `json:"verifierAddress,omitempty"` - VerifierProxyAddress string `json:"verifierProxyAddress,omitempty"` - ServerURL string `json:"serverURL,omitempty"` - ServerPublicKey string `json:"serverPublicKey,omitempty"` - Servers *string `json:"servers,omitempty"` -} - -type CreateMercuryNetworkStackPayload struct { - NetworkStack *MercuryNetworkStack `json:"networkStack,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type CreateNetworkInput struct { - ChainID string `json:"chainID,omitempty"` - ChainType ChainType `json:"chainType,omitempty"` - Name string `json:"name,omitempty"` - NativeToken string `json:"nativeToken,omitempty"` - NativeTokenContractAddress *string `json:"nativeTokenContractAddress,omitempty"` - ConfigContractAddress *string `json:"configContractAddress,omitempty"` - LinkUSDProxyAddress *string `json:"linkUSDProxyAddress,omitempty"` - NativeUSDProxyAddress *string `json:"nativeUSDProxyAddress,omitempty"` - LinkContractAddress *string `json:"linkContractAddress,omitempty"` - FlagsContractAddress *string `json:"flagsContractAddress,omitempty"` - LinkFunding *string `json:"linkFunding,omitempty"` - BillingAdminAccessControllerAddress *string `json:"billingAdminAccessControllerAddress,omitempty"` - RequesterAdminAccessControllerAddress *string `json:"requesterAdminAccessControllerAddress,omitempty"` - ExplorerAPIKey *string `json:"explorerAPIKey,omitempty"` - ExplorerAPIURL *string `json:"explorerAPIURL,omitempty"` -} - -type CreateNetworkPayload struct { - Network *Network `json:"network,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type CreateNodeInput struct { - Name string `json:"name,omitempty"` - PublicKey string `json:"publicKey,omitempty"` - NodeOperatorID string `json:"nodeOperatorID,omitempty"` - SupportedCategoryIDs []string `json:"supportedCategoryIDs,omitempty"` - SupportedProducts []ProductType `json:"supportedProducts,omitempty"` -} - -type CreateNodeOperatorInput struct { - Keys []string `json:"keys,omitempty"` - Name string `json:"name,omitempty"` - Email *string `json:"email,omitempty"` - Website *string `json:"website,omitempty"` -} - -type CreateNodeOperatorPayload struct { - NodeOperator *NodeOperator `json:"nodeOperator,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type CreateNodePayload struct { - Node *Node `json:"node,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type CreateRelayerAccountInput struct { - RelayerID string `json:"relayerID,omitempty"` -} - -type CreateRelayerAccountPayload struct { - RelayerAccount *RelayerAccount `json:"relayerAccount,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type CreateRelayerInput struct { - Name string `json:"name,omitempty"` - NetworkID string `json:"networkID,omitempty"` - Config string `json:"config,omitempty"` - URL *RelayerURL `json:"url,omitempty"` -} - -type CreateRelayerPayload struct { - Relayer *Relayer `json:"relayer,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type CreateUserInput struct { - Email string `json:"email,omitempty"` - Name string `json:"name,omitempty"` - Password string `json:"password,omitempty"` - Role UserRole `json:"role,omitempty"` -} - -type CreateUserPayload struct { - User *User `json:"user,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type CreateVaultInput struct { - Name string `json:"name,omitempty"` - Address string `json:"address,omitempty"` - VaultType VaultType `json:"vaultType,omitempty"` - SupportedProducts []ProductType `json:"supportedProducts,omitempty"` - NetworkID string `json:"networkID,omitempty"` -} - -type CreateVaultPayload struct { - Vault *Vault `json:"vault,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type CreateWebhookInput struct { - Name string `json:"name,omitempty"` - EndpointURL string `json:"endpointURL,omitempty"` -} - -type CreateWebhookPayload struct { - Webhook *Webhook `json:"webhook,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type Don struct { - ID string `json:"id,omitempty"` - Network *Network `json:"network,omitempty"` - ExecutionType DONExecutionType `json:"executionType,omitempty"` - Jobs []*Job `json:"jobs,omitempty"` -} - -type DONBasic struct { - ID string `json:"id,omitempty"` - ExecutionType DONExecutionType `json:"executionType,omitempty"` - Jobs []*JobBasic `json:"jobs,omitempty"` -} - -type DeactivateBootstrapNodeInput struct { - ID string `json:"id,omitempty"` - ContractType ContractType `json:"contractType,omitempty"` -} - -type DeactivateBootstrapNodePayload struct { - Node *Node `json:"node,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type DeleteContractInput struct { - ChainID string `json:"chainID,omitempty"` - ContractID string `json:"contractID,omitempty"` -} - -type DeleteContractPayload struct { - Errors []Error `json:"errors,omitempty"` -} - -type DeleteFeedInput struct { - ID string `json:"id,omitempty"` -} - -type DeleteFeedPayload struct { - Feed *Feed `json:"feed,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type DeleteJobInput struct { - ID string `json:"id,omitempty"` -} - -type DeleteJobPayload struct { - Job *Job `json:"job,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type DeleteNodeInput struct { - ID string `json:"id,omitempty"` -} - -type DeleteNodePayload struct { - Node *Node `json:"node,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type DeleteVaultInput struct { - ID string `json:"id,omitempty"` -} - -type DeleteVaultPayload struct { - Vault *Vault `json:"vault,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type DeleteWebhookInput struct { - ID string `json:"id,omitempty"` -} - -type DeleteWebhookPayload struct { - Webhook *Webhook `json:"webhook,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type DeleteWorkflowRunInput struct { - WorkflowRunID string `json:"workflowRunID,omitempty"` -} - -type DeleteWorkflowRunPayload struct { - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type DeployContractInput struct { - ChainID string `json:"chainID,omitempty"` - ContractID string `json:"contractID,omitempty"` -} - -type DeployContractPayload struct { - Errors []Error `json:"errors,omitempty"` - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` -} - -type DeployMercuryV03NetworkStackInput struct { - NetworkStackID string `json:"networkStackID,omitempty"` -} - -type DeployMercuryV03NetworkStackPayload struct { - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type DeploySetStorageContractInput struct { - StorageID string `json:"storageID,omitempty"` -} - -type DeploySetStorageContractPayload struct { - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type DeployTokenInput struct { - Symbol string `json:"symbol,omitempty"` -} - -type DeployTokenPayload struct { - WorkflowRunsAndContracts []*WorkflowRunAndContract `json:"workflowRunsAndContracts,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type DeregisterTestTokenInput struct { - LaneLegID string `json:"laneLegID,omitempty"` -} - -type DeregisterTestTokenPayload struct { - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type DisableNodeInput struct { - ID string `json:"id,omitempty"` -} - -type DisableNodePayload struct { - Node *Node `json:"node,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type DisableRelayerInput struct { - ID string `json:"id,omitempty"` -} - -type DisableRelayerPayload struct { - Relayer *Relayer `json:"relayer,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type DisableUserInput struct { - ID string `json:"id,omitempty"` -} - -type DisableUserPayload struct { - User *User `json:"user,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type EVMBridgedToken struct { - Token string `json:"token,omitempty"` - Address string `json:"address,omitempty"` - TokenPoolType TokenPoolType `json:"tokenPoolType,omitempty"` - PriceType TokenPriceType `json:"priceType,omitempty"` - Price *string `json:"price,omitempty"` - PriceFeed *PriceFeed `json:"priceFeed,omitempty"` -} - -type EnableNodeInput struct { - ID string `json:"id,omitempty"` -} - -type EnableNodePayload struct { - Node *Node `json:"node,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type EnableRelayerInput struct { - ID string `json:"id,omitempty"` -} - -type EnableRelayerPayload struct { - Relayer *Relayer `json:"relayer,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type Feed struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Status FeedStatus `json:"status,omitempty"` - Network *Network `json:"network,omitempty"` - Proxy *AggregatorProxy `json:"proxy,omitempty"` - Aggregators []*Aggregator `json:"aggregators,omitempty"` - WorkflowRuns []*WorkflowRun `json:"workflowRuns,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` -} - -type FeedsFilters struct { - ChainID *string `json:"chainID,omitempty"` - ChainType *ChainType `json:"chainType,omitempty"` - Name *string `json:"name,omitempty"` - NetworkID *string `json:"networkID,omitempty"` - ProxyAddress *string `json:"proxyAddress,omitempty"` - Limit *string `json:"limit,omitempty"` - Offset *string `json:"offset,omitempty"` -} - -type FeedsInput struct { - Filter *FeedsFilters `json:"filter,omitempty"` -} - -type GauntletReport struct { - ID string `json:"id,omitempty"` - TraceID string `json:"traceID,omitempty"` - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` - TransactionHash *string `json:"transactionHash,omitempty"` - ReportID string `json:"reportID,omitempty"` - Timestamp Time `json:"timestamp,omitempty"` - Op string `json:"op,omitempty"` - Input string `json:"input,omitempty"` - Output *string `json:"output,omitempty"` - Requirements *string `json:"requirements,omitempty"` - Config string `json:"config,omitempty"` - Subops *string `json:"subops,omitempty"` - Events *string `json:"events,omitempty"` - Snapshot *string `json:"snapshot,omitempty"` - Error *string `json:"error,omitempty"` - TraceExtra *string `json:"traceExtra,omitempty"` -} - -type GauntletReportsInput struct { - TraceID *string `json:"traceID,omitempty"` - WorkflowRunID *int `json:"workflowRunID,omitempty"` - TransactionHash *string `json:"transactionHash,omitempty"` -} - -type ImportAggregatorInput struct { - Name string `json:"name,omitempty"` - ContractAddress string `json:"contractAddress,omitempty"` - Template string `json:"template,omitempty"` - CategoryID string `json:"categoryID,omitempty"` -} - -type ImportChainInput struct { - NetworkID string `json:"networkID,omitempty"` - Template string `json:"template,omitempty"` - // The Display String lets a user differentiate multiple CCIP chains on the same network. It is not unique and used for display purposes only. - DisplayName *string `json:"displayName,omitempty"` -} - -type ImportChainPayload struct { - Errors []Error `json:"errors,omitempty"` - Chain *CCIPChain `json:"chain,omitempty"` -} - -type ImportFeedAggregatorInput struct { - FeedID string `json:"feedID,omitempty"` - Aggregator *ImportAggregatorInput `json:"aggregator,omitempty"` -} - -type ImportFeedAggregatorPayload struct { - Aggregator *Aggregator `json:"aggregator,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type ImportFeedInput struct { - Name string `json:"name,omitempty"` - NetworkID string `json:"networkID,omitempty"` - Proxy *ImportProxyInput `json:"proxy,omitempty"` - Aggregators []*ImportAggregatorInput `json:"aggregators,omitempty"` -} - -type ImportFeedPayload struct { - Feed *Feed `json:"feed,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type ImportKeystoneWorkflowInput struct { - CategoryID string `json:"categoryID,omitempty"` - NetworkID string `json:"networkID,omitempty"` - Template string `json:"template,omitempty"` -} - -type ImportKeystoneWorkflowPayload struct { - Workflow *KeystoneWorkflow `json:"workflow,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type ImportLaneInput struct { - ChainAid string `json:"chainAID,omitempty"` - ChainBid string `json:"chainBID,omitempty"` - Template string `json:"template,omitempty"` - // The Display String lets a user differentiate multiple CCIP chains on the same network. It is not unique and used for display purposes only. - DisplayName *string `json:"displayName,omitempty"` -} - -type ImportLanePayload struct { - Errors []Error `json:"errors,omitempty"` - Lane *CCIPLane `json:"lane,omitempty"` -} - -type ImportMercuryFeedInput struct { - Name string `json:"name,omitempty"` - ExternalFeedID string `json:"externalFeedID,omitempty"` - NetworkStackID string `json:"networkStackID,omitempty"` - FromBlock string `json:"fromBlock,omitempty"` - Template string `json:"template,omitempty"` -} - -type ImportMercuryFeedPayload struct { - Feed *MercuryFeed `json:"feed,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type ImportMercuryV03FeedInput struct { - Name string `json:"name,omitempty"` - ExternalFeedID string `json:"externalFeedID,omitempty"` - Template string `json:"template,omitempty"` - CategoryID string `json:"categoryID,omitempty"` -} - -type ImportMercuryV03FeedPayload struct { - Feed *MercuryV03Feed `json:"feed,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type ImportMercuryV03NetworkStackInput struct { - NetworkID string `json:"networkID,omitempty"` - VerifierAddress string `json:"verifierAddress,omitempty"` - VerifierProxyAddress string `json:"verifierProxyAddress,omitempty"` - RewardBankAddress string `json:"rewardBankAddress,omitempty"` - FeeManagerAddress string `json:"feeManagerAddress,omitempty"` - MercuryServerURL string `json:"mercuryServerURL,omitempty"` - MercuryServerPubKey string `json:"mercuryServerPubKey,omitempty"` - Servers *string `json:"servers,omitempty"` -} - -type ImportMercuryV03NetworkStackPayload struct { - NetworkStack *MercuryV03NetworkStack `json:"networkStack,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type ImportOCR3CapabilityInput struct { - CategoryID string `json:"categoryID,omitempty"` - NetworkID string `json:"networkID,omitempty"` - Template string `json:"template,omitempty"` -} - -type ImportOCR3CapabilityPayload struct { - Ocr3Capability *OCR3Capability `json:"ocr3Capability,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type ImportProxyInput struct { - ContractAddress string `json:"contractAddress,omitempty"` - AccessControllerAddress *string `json:"accessControllerAddress,omitempty"` - AggregatorAddress string `json:"aggregatorAddress,omitempty"` -} - -type ImportTokenPoolInput struct { - ID string `json:"id,omitempty"` - Template string `json:"template,omitempty"` -} - -type ImportTokenPoolPayload struct { - Errors []Error `json:"errors,omitempty"` - Chain *CCIPChain `json:"chain,omitempty"` -} - -type Job struct { - ID string `json:"id,omitempty"` - UUID string `json:"uuid,omitempty"` - Type JobType `json:"type,omitempty"` - Ocr2PluginType *OCR2PluginType `json:"ocr2PluginType,omitempty"` - Status JobStatus `json:"status,omitempty"` - NodeOperator *NodeOperator `json:"nodeOperator,omitempty"` - Node *Node `json:"node,omitempty"` - IsBootstrap bool `json:"isBootstrap,omitempty"` - Config JobConfig `json:"config,omitempty"` - Spec *string `json:"spec,omitempty"` - ProposalChanged bool `json:"proposalChanged,omitempty"` - AssignableNodes []*Node `json:"assignableNodes,omitempty"` - CanPropose bool `json:"canPropose,omitempty"` - CanRevoke bool `json:"canRevoke,omitempty"` - Proposals []*JobProposal `json:"proposals,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` -} - -type JobBasic struct { - ID string `json:"id,omitempty"` - UUID string `json:"uuid,omitempty"` - Type JobType `json:"type,omitempty"` - Ocr2PluginType *OCR2PluginType `json:"ocr2PluginType,omitempty"` - Status JobStatus `json:"status,omitempty"` - IsBootstrap bool `json:"isBootstrap,omitempty"` -} - -type JobConfigEmpty struct { - Empty bool `json:"_empty,omitempty"` -} - -func (JobConfigEmpty) IsJobConfig() {} - -type JobConfigEmptyInput struct { - Empty *bool `json:"_empty,omitempty"` -} - -type JobConfigInput struct { - Ocr1 *JobConfigOCR1Input `json:"ocr1,omitempty"` - Ocr2Median *JobConfigOCR2MedianInput `json:"ocr2Median,omitempty"` - Ocr2Mercury *JobConfigOCR2MercuryInput `json:"ocr2Mercury,omitempty"` - Ocr2CCIPCommit *JobConfigEmptyInput `json:"ocr2CCIPCommit,omitempty"` - Ocr2CCIPExecution *JobConfigEmptyInput `json:"ocr2CCIPExecution,omitempty"` - Ocr2CCIPRebalancer *JobConfigEmptyInput `json:"ocr2CCIPRebalancer,omitempty"` -} - -type JobConfigOcr1 struct { - Apis []string `json:"apis,omitempty"` -} - -func (JobConfigOcr1) IsJobConfig() {} - -type JobConfigOCR1Input struct { - Apis []string `json:"apis,omitempty"` -} - -type JobConfigOCR2Median struct { - Apis []string `json:"apis,omitempty"` -} - -func (JobConfigOCR2Median) IsJobConfig() {} - -type JobConfigOCR2MedianInput struct { - Apis []string `json:"apis,omitempty"` -} - -type JobConfigOCR2Mercury struct { - Apis []string `json:"apis,omitempty"` -} - -func (JobConfigOCR2Mercury) IsJobConfig() {} - -type JobConfigOCR2MercuryInput struct { - Apis []string `json:"apis,omitempty"` - CrossApis []string `json:"crossApis,omitempty"` -} - -type JobProposal struct { - ID string `json:"id,omitempty"` - Version string `json:"version,omitempty"` - Status JobProposalStatus `json:"status,omitempty"` - Spec string `json:"spec,omitempty"` - Job *Job `json:"job,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` - UpdatedAt Time `json:"updatedAt,omitempty"` - ProposedAt *Time `json:"proposedAt,omitempty"` - ResponseReceivedAt *Time `json:"responseReceivedAt,omitempty"` -} - -type KeystoneWorkflow struct { - ID string `json:"id,omitempty"` - WorkflowSpec string `json:"workflowSpec,omitempty"` - WorkflowOwner string `json:"workflowOwner,omitempty"` - ExternalWorkflowID string `json:"externalWorkflowID,omitempty"` - Don *Don `json:"don,omitempty"` - Name string `json:"name,omitempty"` - Category *Category `json:"category,omitempty"` -} - -type KeystoneWorkflowMutations struct { - ImportWorkflow *ImportKeystoneWorkflowPayload `json:"importWorkflow,omitempty"` - UpdateWorkflow *UpdateKeystoneWorkflowPayload `json:"updateWorkflow,omitempty"` -} - -type KeystoneWorkflowQueries struct { - Workflow *KeystoneWorkflow `json:"workflow,omitempty"` - Workflows []*KeystoneWorkflow `json:"workflows,omitempty"` -} - -type ListAggregatorsFilter struct { - NetworkID *string `json:"networkID,omitempty"` - ContractAddress *string `json:"contractAddress,omitempty"` -} - -type ListRelayersFilter struct { - Enabled *bool `json:"enabled,omitempty"` -} - -type ListWebhookCallsFilter struct { - State *WebhookCallState `json:"state,omitempty"` -} - -type LoginInput struct { - Email string `json:"email,omitempty"` - Password string `json:"password,omitempty"` -} - -type LoginPayload struct { - Session *Session `json:"session,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type LogoutPayload struct { - Session *Session `json:"session,omitempty"` -} - -type MarkStaleJobsInput struct { - Ids []string `json:"ids,omitempty"` -} - -type MarkStaleJobsPayload struct { - Jobs []*Job `json:"jobs,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type MercuryFeed struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - ExternalFeedID string `json:"externalFeedID,omitempty"` - NetworkStack *MercuryNetworkStack `json:"networkStack,omitempty"` - FromBlock string `json:"fromBlock,omitempty"` - Template string `json:"template,omitempty"` - Don *Don `json:"don,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` - UpdatedAt Time `json:"updatedAt,omitempty"` -} - -type MercuryFeedsFilters struct { - Name *string `json:"name,omitempty"` - NetworkID *string `json:"networkID,omitempty"` - VerifierProxyAddress *string `json:"verifierProxyAddress,omitempty"` - Limit *string `json:"limit,omitempty"` - Offset *string `json:"offset,omitempty"` -} - -type MercuryFeedsInput struct { - Filter *MercuryFeedsFilters `json:"filter,omitempty"` -} - -type MercuryMutations struct { - CreateNetworkStack *CreateMercuryNetworkStackPayload `json:"createNetworkStack,omitempty"` - ImportFeed *ImportMercuryFeedPayload `json:"importFeed,omitempty"` - UpdateFeed *UpdateMercuryFeedPayload `json:"updateFeed,omitempty"` - UpdateNetworkStack *UpdateMercuryNetworkStackPayload `json:"updateNetworkStack,omitempty"` -} - -type MercuryNetworkStack struct { - ID string `json:"id,omitempty"` - Network *Network `json:"network,omitempty"` - VerifierAddress string `json:"verifierAddress,omitempty"` - VerifierProxyAddress string `json:"verifierProxyAddress,omitempty"` - ServerURL string `json:"serverURL,omitempty"` - ServerPublicKey string `json:"serverPublicKey,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` - UpdatedAt Time `json:"updatedAt,omitempty"` - Servers []*MercuryServer `json:"servers,omitempty"` -} - -type MercuryQueries struct { - NetworkStacks []*MercuryNetworkStack `json:"networkStacks,omitempty"` - NetworkStack *MercuryNetworkStack `json:"networkStack,omitempty"` - Feed *MercuryFeed `json:"feed,omitempty"` - Feeds []*MercuryFeed `json:"feeds,omitempty"` -} - -type MercuryServer struct { - URL string `json:"url,omitempty"` - PublicKey string `json:"publicKey,omitempty"` -} - -type MercuryV03Feed struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - ExternalFeedID string `json:"externalFeedID,omitempty"` - Verifiers []*MercuryV03Verifier `json:"verifiers,omitempty"` - ReportSchemaVersion ReportSchemaVersion `json:"reportSchemaVersion,omitempty"` - Template string `json:"template,omitempty"` - Don *Don `json:"don,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` - UpdatedAt Time `json:"updatedAt,omitempty"` - ArchivedAt *Time `json:"archivedAt,omitempty"` - Category *Category `json:"category,omitempty"` -} - -type MercuryV03FeedFilter struct { - IsArchived *bool `json:"isArchived,omitempty"` - TransmitToServer *bool `json:"transmitToServer,omitempty"` -} - -type MercuryV03Mutations struct { - ArchiveFeed *ArchiveFeedPayload `json:"archiveFeed,omitempty"` - ArchiveNetworkStack *ArchiveNetworkStackPayload `json:"archiveNetworkStack,omitempty"` - AddVerificationProvider *AddVerificationProviderPayload `json:"addVerificationProvider,omitempty"` - RemoveVerificationProvider *RemoveVerificationProviderPayload `json:"removeVerificationProvider,omitempty"` - AddNetworkStack *AddMercuryV03NetworkStackPayload `json:"addNetworkStack,omitempty"` - DeployNetworkStack *DeployMercuryV03NetworkStackPayload `json:"deployNetworkStack,omitempty"` - ImportFeed *ImportMercuryV03FeedPayload `json:"importFeed,omitempty"` - ImportNetworkStack *ImportMercuryV03NetworkStackPayload `json:"importNetworkStack,omitempty"` - TransferOwnership *TransferOwnershipPayload `json:"transferOwnership,omitempty"` - UpdateNetworkStack *UpdateMercuryV03NetworkStackPayload `json:"updateNetworkStack,omitempty"` - UpdateFeed *UpdateMercuryV03FeedPayload `json:"updateFeed,omitempty"` - VerifyContract *VerifyMercuryV03ContractPayload `json:"verifyContract,omitempty"` -} - -type MercuryV03NetworkStack struct { - ID string `json:"id,omitempty"` - Network *Network `json:"network,omitempty"` - Status NetworkStackStatus `json:"status,omitempty"` - VerifierAddress *string `json:"verifierAddress,omitempty"` - VerifierProxyAddress *string `json:"verifierProxyAddress,omitempty"` - RewardBankAddress *string `json:"rewardBankAddress,omitempty"` - FeeManagerAddress *string `json:"feeManagerAddress,omitempty"` - MercuryServerURL string `json:"mercuryServerURL,omitempty"` - MercuryServerPubKey string `json:"mercuryServerPubKey,omitempty"` - Contracts []*Contract `json:"contracts,omitempty"` - WorkflowRuns []*WorkflowRun `json:"workflowRuns,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` - UpdatedAt Time `json:"updatedAt,omitempty"` - ArchivedAt *Time `json:"archivedAt,omitempty"` - Servers []*MercuryServer `json:"servers,omitempty"` -} - -type MercuryV03NetworkStackFilter struct { - IsArchived *bool `json:"isArchived,omitempty"` -} - -type MercuryV03Queries struct { - NetworkStack *MercuryV03NetworkStack `json:"networkStack,omitempty"` - NetworkStacks []*MercuryV03NetworkStack `json:"networkStacks,omitempty"` - Feed *MercuryV03Feed `json:"feed,omitempty"` - Feeds []*MercuryV03Feed `json:"feeds,omitempty"` -} - -type MercuryV03Verifier struct { - ID string `json:"id,omitempty"` - NetworkStack *MercuryV03NetworkStack `json:"networkStack,omitempty"` - NetworkStackType NetworkStackType `json:"networkStackType,omitempty"` -} - -type Mutation struct { -} - -type Network struct { - ID string `json:"id,omitempty"` - ChainID string `json:"chainID,omitempty"` - ChainType ChainType `json:"chainType,omitempty"` - Name string `json:"name,omitempty"` - NativeToken string `json:"nativeToken,omitempty"` - Archived bool `json:"archived,omitempty"` - NativeTokenContractAddress *string `json:"nativeTokenContractAddress,omitempty"` - ConfigContractAddress *string `json:"configContractAddress,omitempty"` - LinkUSDProxyAddress *string `json:"linkUSDProxyAddress,omitempty"` - NativeUSDProxyAddress *string `json:"nativeUSDProxyAddress,omitempty"` - LinkContractAddress *string `json:"linkContractAddress,omitempty"` - FlagsContractAddress *string `json:"flagsContractAddress,omitempty"` - LinkFunding string `json:"linkFunding,omitempty"` - BillingAdminAccessControllerAddress *string `json:"billingAdminAccessControllerAddress,omitempty"` - RequesterAdminAccessControllerAddress *string `json:"requesterAdminAccessControllerAddress,omitempty"` - IconName *string `json:"iconName,omitempty"` - ExplorerURL *string `json:"explorerURL,omitempty"` - Relayers []*Relayer `json:"relayers,omitempty"` - Vaults []*Vault `json:"vaults,omitempty"` - ExplorerAPIKey *string `json:"explorerAPIKey,omitempty"` - ExplorerAPIURL *string `json:"explorerAPIURL,omitempty"` -} - -type NetworksFilters struct { - Archived *bool `json:"archived,omitempty"` - ChainID *string `json:"chainID,omitempty"` - ChainType *ChainType `json:"chainType,omitempty"` - Name *string `json:"name,omitempty"` -} - -type NetworksInput struct { - Filter *NetworksFilters `json:"filter,omitempty"` -} - -type Node struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - PublicKey *string `json:"publicKey,omitempty"` - ChainConfigs []*NodeChainConfig `json:"chainConfigs,omitempty"` - Connected bool `json:"connected,omitempty"` - Enabled bool `json:"enabled,omitempty"` - Metadata *NodeMetadata `json:"metadata,omitempty"` - NodeOperator *NodeOperator `json:"nodeOperator,omitempty"` - Version *string `json:"version,omitempty"` - SupportedProducts []ProductType `json:"supportedProducts,omitempty"` - Categories []*Category `json:"categories,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` -} - -type NodeChainConfig struct { - ID string `json:"id,omitempty"` - Network *Network `json:"network,omitempty"` - AccountAddress string `json:"accountAddress,omitempty"` - AdminAddress string `json:"adminAddress,omitempty"` - Ocr1Config *NodeOCR1Config `json:"ocr1Config,omitempty"` - Ocr1BootstrapVerified bool `json:"ocr1BootstrapVerified,omitempty"` - Ocr2Config *NodeOCR2Config `json:"ocr2Config,omitempty"` - Ocr2BootstrapVerified bool `json:"ocr2BootstrapVerified,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` -} - -type NodeConnectionInfo struct { - PublicKey string `json:"publicKey,omitempty"` - RPCURL string `json:"rpcURL,omitempty"` -} - -type NodeMetadata struct { - JobCount int `json:"jobCount,omitempty"` -} - -type NodeOCR1Config struct { - Enabled bool `json:"enabled,omitempty"` - IsBootstrap bool `json:"isBootstrap,omitempty"` - Multiaddr *string `json:"multiaddr,omitempty"` - P2pKeyBundle *NodeOCR1ConfigP2PKeyBundle `json:"p2pKeyBundle,omitempty"` - OcrKeyBundle *NodeOCR1ConfigOCRKeyBundle `json:"ocrKeyBundle,omitempty"` -} - -type NodeOCR1ConfigOCRKeyBundle struct { - BundleID string `json:"bundleID,omitempty"` - ConfigPublicKey string `json:"configPublicKey,omitempty"` - OffchainPublicKey string `json:"offchainPublicKey,omitempty"` - OnchainSigningAddress string `json:"onchainSigningAddress,omitempty"` -} - -type NodeOCR1ConfigP2PKeyBundle struct { - PeerID string `json:"peerID,omitempty"` - PublicKey string `json:"publicKey,omitempty"` -} - -type NodeOCR2Config struct { - Enabled bool `json:"enabled,omitempty"` - IsBootstrap bool `json:"isBootstrap,omitempty"` - Multiaddr *string `json:"multiaddr,omitempty"` - ForwarderAddress *string `json:"forwarderAddress,omitempty"` - P2pKeyBundle *NodeOCR2ConfigP2PKeyBundle `json:"p2pKeyBundle,omitempty"` - OcrKeyBundle *NodeOCR2ConfigOCRKeyBundle `json:"ocrKeyBundle,omitempty"` - Plugins *NodeOCR2ConfigPlugins `json:"plugins,omitempty"` -} - -type NodeOCR2ConfigOCRKeyBundle struct { - BundleID string `json:"bundleID,omitempty"` - ConfigPublicKey string `json:"configPublicKey,omitempty"` - OffchainPublicKey string `json:"offchainPublicKey,omitempty"` - OnchainSigningAddress string `json:"onchainSigningAddress,omitempty"` -} - -type NodeOCR2ConfigP2PKeyBundle struct { - PeerID string `json:"peerID,omitempty"` - PublicKey string `json:"publicKey,omitempty"` -} - -type NodeOCR2ConfigPlugins struct { - CcipCommit bool `json:"ccipCommit,omitempty"` - CcipExecution bool `json:"ccipExecution,omitempty"` - CcipRebalancer bool `json:"ccipRebalancer,omitempty"` - Median bool `json:"median,omitempty"` - Mercury bool `json:"mercury,omitempty"` -} - -type NodeOperator struct { - ID string `json:"id,omitempty"` - Keys []string `json:"keys,omitempty"` - Name string `json:"name,omitempty"` - Email string `json:"email,omitempty"` - Website string `json:"website,omitempty"` - Metadata *NodeOperatorMetadata `json:"metadata,omitempty"` - Nodes []*Node `json:"nodes,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` -} - -type NodeOperatorMetadata struct { - NodeCount int `json:"nodeCount,omitempty"` - JobCount int `json:"jobCount,omitempty"` -} - -type NodesFilters struct { - NetworkID *string `json:"networkID,omitempty"` -} - -type NodesInput struct { - Filter *NodesFilters `json:"filter,omitempty"` -} - -type OCR3Capability struct { - ID string `json:"id,omitempty"` - ContractAddress string `json:"contractAddress,omitempty"` - Name string `json:"name,omitempty"` - BootstrapMultiaddrs []string `json:"bootstrapMultiaddrs,omitempty"` - Template string `json:"template,omitempty"` - Category *Category `json:"category,omitempty"` - Don *Don `json:"don,omitempty"` -} - -type OCR3CapabilityMutations struct { - ImportOCR3Capability *ImportOCR3CapabilityPayload `json:"importOCR3Capability,omitempty"` - UpdateOCR3Capability *UpdateOCR3CapabilityPayload `json:"updateOCR3Capability,omitempty"` -} - -type OCR3CapabilityQueries struct { - Ocr3Capability *OCR3Capability `json:"ocr3Capability,omitempty"` - Ocr3Capabilities []*OCR3Capability `json:"ocr3Capabilities,omitempty"` -} - -type PriceFeed struct { - AggregatorAddress string `json:"aggregatorAddress,omitempty"` - Multiplier string `json:"multiplier,omitempty"` -} - -type Profile struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Email string `json:"email,omitempty"` - Role UserRole `json:"role,omitempty"` - Permits []string `json:"permits,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` -} - -type ProposeJobInput struct { - ID string `json:"id,omitempty"` -} - -type ProposeJobPayload struct { - Job *Job `json:"job,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type Query struct { -} - -type ReadAccessController struct { - Address string `json:"address,omitempty"` -} - -type Relayer struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - URL *URL `json:"url,omitempty"` - Config string `json:"config,omitempty"` - IsEnabled bool `json:"isEnabled,omitempty"` - Network *Network `json:"network,omitempty"` - Accounts []*RelayerAccount `json:"accounts,omitempty"` -} - -type RelayerAccount struct { - ID string `json:"id,omitempty"` - Relayer *Relayer `json:"relayer,omitempty"` - Address string `json:"address,omitempty"` - NativeBalance string `json:"nativeBalance,omitempty"` - LinkBalance string `json:"linkBalance,omitempty"` -} - -type RelayerURL struct { - Websocket string `json:"websocket,omitempty"` - HTTP string `json:"http,omitempty"` -} - -type RemoveLiquidityInput struct { - ChainID string `json:"chainID,omitempty"` - TokenPoolContractID string `json:"tokenPoolContractID,omitempty"` - Amount string `json:"amount,omitempty"` -} - -type RemoveLiquidityPayload struct { - Errors []Error `json:"errors,omitempty"` - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` -} - -type RemoveVerificationProviderInput struct { - FeedID string `json:"feedID,omitempty"` - NetworkStackID string `json:"networkStackID,omitempty"` -} - -type RemoveVerificationProviderPayload struct { - Feed *MercuryV03Feed `json:"feed,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type RetryActionRunInput struct { - ActionRunID string `json:"actionRunID,omitempty"` -} - -type RetryActionRunPayload struct { - Status ActionRunStatus `json:"status,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type RetryWebhookCallInput struct { - WebhookCallID string `json:"webhookCallID,omitempty"` -} - -type RetryWebhookCallPayload struct { - WebhookCall *WebhookCall `json:"webhookCall,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type RevokeJobInput struct { - ID string `json:"id,omitempty"` -} - -type RevokeJobPayload struct { - Job *Job `json:"job,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type Role struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Permits []string `json:"permits,omitempty"` -} - -type RunCCIPCommandInput struct { - Command CCIPCommand `json:"command,omitempty"` - LaneLegID string `json:"laneLegID,omitempty"` - Upgrade *bool `json:"upgrade,omitempty"` -} - -type RunCCIPCommandPayload struct { - Errors []Error `json:"errors,omitempty"` - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` -} - -type SendTestWebhookEventInput struct { - WebhookID string `json:"webhookID,omitempty"` -} - -type SendTestWebhookEventPayload struct { - WebhookCall *WebhookCall `json:"webhookCall,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type Session struct { - ID string `json:"id,omitempty"` - Token string `json:"token,omitempty"` - ExpiresAt Time `json:"expiresAt,omitempty"` - Revoked bool `json:"revoked,omitempty"` - Permits []string `json:"permits,omitempty"` -} - -type SetAllowListTokenPoolInput struct { - ChainID string `json:"chainID,omitempty"` - TokenPoolContractID string `json:"tokenPoolContractID,omitempty"` - AllowList []string `json:"allowList,omitempty"` -} - -type SetAllowListTokenPoolPayload struct { - Errors []Error `json:"errors,omitempty"` - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` -} - -type SetPasswordInput struct { - UserID string `json:"userID,omitempty"` - Password string `json:"password,omitempty"` -} - -type SetPasswordPayload struct { - Errors []Error `json:"errors,omitempty"` -} - -type SetupAppInput struct { - Token string `json:"token,omitempty"` - Email string `json:"email,omitempty"` - Name string `json:"name,omitempty"` - Password string `json:"password,omitempty"` -} - -type SetupAppPayload struct { - Errors []Error `json:"errors,omitempty"` -} - -type SpecConfigOffChainReporting1 struct { - Decimals int `json:"decimals,omitempty"` -} - -func (SpecConfigOffChainReporting1) IsAggregatorSpecConfig() {} - -type SpecConfigOffChainReporting2 struct { - Decimals int `json:"decimals,omitempty"` -} - -func (SpecConfigOffChainReporting2) IsAggregatorSpecConfig() {} - -type StorageContract struct { - ID string `json:"id,omitempty"` - Network *Network `json:"network,omitempty"` - DisplayName *string `json:"displayName,omitempty"` - Template string `json:"template,omitempty"` - Contract *Contract `json:"contract,omitempty"` - WorkflowRuns []*WorkflowRun `json:"workflowRuns,omitempty"` -} - -type StorageContractFilter struct { - NetworkID *string `json:"networkID,omitempty"` -} - -// Grouping of all mutations related to the Storage contract resource. -type StorageMutations struct { - // addStorageContract adds a new storage contract to the database and creates - // a single new resource. - AddStorageContract *AddStorageContractPayload `json:"addStorageContract,omitempty"` - // deploySetStorageContract deploys a new storage contract to the network and - // sets the value on chain to the value provided from the template of the storage. - DeploySetStorageContract *DeploySetStorageContractPayload `json:"deploySetStorageContract,omitempty"` -} - -// Grouping of all queries related to the Storage contract resource. -type StorageQueries struct { - StorageContracts []*StorageContract `json:"storageContracts,omitempty"` - StorageContract *StorageContract `json:"storageContract,omitempty"` -} - -type SyncAggregatorInput struct { - ID string `json:"id,omitempty"` -} - -type SyncAggregatorPayload struct { - Aggregator *Aggregator `json:"aggregator,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type SyncAggregatorProxyInput struct { - ID string `json:"id,omitempty"` -} - -type SyncAggregatorProxyPayload struct { - AggregatorProxy *AggregatorProxy `json:"aggregatorProxy,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type SyncChainInput struct { - ChainID string `json:"chainID,omitempty"` -} - -type SyncChainPayload struct { - Chain *CCIPChain `json:"chain,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type SyncContractsInput struct { - ContractIDs []string `json:"contractIDs,omitempty"` -} - -type SyncContractsPayload struct { - Contracts []*Contract `json:"contracts,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type SyncLaneInput struct { - LaneID string `json:"laneID,omitempty"` -} - -type SyncLanePayload struct { - Lane *CCIPLane `json:"lane,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type Task struct { - Name string `json:"name,omitempty"` - Run *TaskRun `json:"run,omitempty"` -} - -type TaskRun struct { - ID string `json:"id,omitempty"` - Input string `json:"input,omitempty"` - Output string `json:"output,omitempty"` - Status TaskRunStatus `json:"status,omitempty"` - Error *string `json:"error,omitempty"` - TxHash *string `json:"txHash,omitempty"` -} - -type Token struct { - Symbol string `json:"symbol,omitempty"` - Address string `json:"address,omitempty"` -} - -type TransferAdminRoleInput struct { - TokenAdminRegistryID string `json:"tokenAdminRegistryID,omitempty"` - TokenPoolID string `json:"tokenPoolID,omitempty"` - VaultID string `json:"vaultID,omitempty"` -} - -type TransferAdminRolePayload struct { - Errors []Error `json:"errors,omitempty"` - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` -} - -type TransferOwnershipInput struct { - ContractIDs []string `json:"contractIDs,omitempty"` - VaultID string `json:"vaultID,omitempty"` -} - -type TransferOwnershipPayload struct { - Errors []Error `json:"errors,omitempty"` - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` -} - -type URL struct { - Websocket string `json:"websocket,omitempty"` - HTTP *string `json:"http,omitempty"` -} - -type UnarchiveNetworkInput struct { - ID string `json:"id,omitempty"` -} - -type UnarchiveNetworkPayload struct { - Network *Network `json:"network,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateAggregatorDetailsInput struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - CategoryID string `json:"categoryID,omitempty"` -} - -type UpdateAggregatorDetailsPayload struct { - Aggregator *Aggregator `json:"aggregator,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateAggregatorInput struct { - ID string `json:"id,omitempty"` - AggregatorTemplate *string `json:"aggregatorTemplate,omitempty"` -} - -type UpdateAggregatorPayload struct { - Aggregator *Aggregator `json:"aggregator,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateAggregatorProxyInput struct { - ID string `json:"id,omitempty"` - ContractAddress string `json:"contractAddress,omitempty"` -} - -type UpdateAggregatorProxyPayload struct { - ID string `json:"id,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateCCIPChainInput struct { - ID string `json:"id,omitempty"` - Template string `json:"template,omitempty"` -} - -type UpdateCCIPChainPayload struct { - Chain *CCIPChain `json:"chain,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateCategoryInput struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Color *string `json:"color,omitempty"` -} - -type UpdateCategoryPayload struct { - Category *Category `json:"category,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateFeedInput struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` -} - -type UpdateFeedPayload struct { - Feed *Feed `json:"feed,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateKeystoneWorkflowInput struct { - ID string `json:"id,omitempty"` - Template string `json:"template,omitempty"` - CategoryID string `json:"categoryID,omitempty"` -} - -type UpdateKeystoneWorkflowPayload struct { - Workflow *KeystoneWorkflow `json:"workflow,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateLaneInput struct { - Template *string `json:"template,omitempty"` - UpdateStartBlocks *bool `json:"updateStartBlocks,omitempty"` - LegA *CCIPLaneChainUpdateInput `json:"legA,omitempty"` - LegB *CCIPLaneChainUpdateInput `json:"legB,omitempty"` -} - -type UpdateLanePayload struct { - Errors []Error `json:"errors,omitempty"` - Lane *CCIPLane `json:"lane,omitempty"` -} - -type UpdateMercuryFeedInput struct { - ID string `json:"id,omitempty"` - FromBlock string `json:"fromBlock,omitempty"` - Template *string `json:"template,omitempty"` -} - -type UpdateMercuryFeedPayload struct { - Feed *MercuryFeed `json:"feed,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateMercuryNetworkStackInput struct { - ID string `json:"id,omitempty"` - VerifierAddress string `json:"verifierAddress,omitempty"` - VerifierProxyAddress string `json:"verifierProxyAddress,omitempty"` - ServerURL string `json:"serverURL,omitempty"` - ServerPublicKey string `json:"serverPublicKey,omitempty"` - Servers *string `json:"servers,omitempty"` -} - -type UpdateMercuryNetworkStackPayload struct { - NetworkStack *MercuryNetworkStack `json:"networkStack,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateMercuryV03FeedInput struct { - ID string `json:"id,omitempty"` - Template string `json:"template,omitempty"` - CategoryID string `json:"categoryID,omitempty"` -} - -type UpdateMercuryV03FeedPayload struct { - Feed *MercuryV03Feed `json:"feed,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateMercuryV03NetworkStackInput struct { - ID string `json:"id,omitempty"` - VerifierAddress string `json:"verifierAddress,omitempty"` - VerifierProxyAddress string `json:"verifierProxyAddress,omitempty"` - RewardBankAddress string `json:"rewardBankAddress,omitempty"` - FeeManagerAddress string `json:"feeManagerAddress,omitempty"` - MercuryServerURL string `json:"mercuryServerURL,omitempty"` - MercuryServerPubKey string `json:"mercuryServerPubKey,omitempty"` - Servers *string `json:"servers,omitempty"` -} - -type UpdateMercuryV03NetworkStackPayload struct { - NetworkStack *MercuryV03NetworkStack `json:"networkStack,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateNetworkInput struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - NativeToken string `json:"nativeToken,omitempty"` - NativeTokenContractAddress *string `json:"nativeTokenContractAddress,omitempty"` - ConfigContractAddress *string `json:"configContractAddress,omitempty"` - LinkUSDProxyAddress *string `json:"linkUSDProxyAddress,omitempty"` - NativeUSDProxyAddress *string `json:"nativeUSDProxyAddress,omitempty"` - LinkContractAddress *string `json:"linkContractAddress,omitempty"` - FlagsContractAddress *string `json:"flagsContractAddress,omitempty"` - LinkFunding *string `json:"linkFunding,omitempty"` - BillingAdminAccessControllerAddress *string `json:"billingAdminAccessControllerAddress,omitempty"` - RequesterAdminAccessControllerAddress *string `json:"requesterAdminAccessControllerAddress,omitempty"` - ExplorerAPIKey *string `json:"explorerAPIKey,omitempty"` - ExplorerAPIURL *string `json:"explorerAPIURL,omitempty"` -} - -type UpdateNetworkPayload struct { - Network *Network `json:"network,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateNodeInput struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - PublicKey string `json:"publicKey,omitempty"` - SupportedCategoryIDs []string `json:"supportedCategoryIDs,omitempty"` - SupportedProducts []ProductType `json:"supportedProducts,omitempty"` -} - -type UpdateNodeOperatorInput struct { - ID string `json:"id,omitempty"` - Keys []string `json:"keys,omitempty"` - Name string `json:"name,omitempty"` - Email string `json:"email,omitempty"` - Website string `json:"website,omitempty"` -} - -type UpdateNodeOperatorPayload struct { - NodeOperator *NodeOperator `json:"nodeOperator,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateNodePayload struct { - Node *Node `json:"node,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateOCR3CapabilityInput struct { - ID string `json:"id,omitempty"` - Template string `json:"template,omitempty"` - CategoryID string `json:"categoryID,omitempty"` -} - -type UpdateOCR3CapabilityPayload struct { - Ocr3Capability *OCR3Capability `json:"ocr3Capability,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdatePasswordInput struct { - OldPassword string `json:"oldPassword,omitempty"` - NewPassword string `json:"newPassword,omitempty"` -} - -type UpdatePasswordPayload struct { - Errors []Error `json:"errors,omitempty"` -} - -type UpdateProfileInput struct { - Name string `json:"name,omitempty"` -} - -type UpdateProfilePayload struct { - Profile *Profile `json:"profile,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateRelayerInput struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - URL *RelayerURL `json:"url,omitempty"` - Config string `json:"config,omitempty"` -} - -type UpdateRelayerPayload struct { - Relayer *Relayer `json:"relayer,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateUserInput struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Email string `json:"email,omitempty"` - Role UserRole `json:"role,omitempty"` -} - -type UpdateUserPayload struct { - User *User `json:"user,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateVaultInput struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Address string `json:"address,omitempty"` - SupportedProducts []ProductType `json:"supportedProducts,omitempty"` -} - -type UpdateVaultPayload struct { - Vault *Vault `json:"vault,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type UpdateWebhookInput struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - EndpointURL string `json:"endpointURL,omitempty"` - Enabled bool `json:"enabled,omitempty"` -} - -type UpdateWebhookPayload struct { - Webhook *Webhook `json:"webhook,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type User struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Email string `json:"email,omitempty"` - Role UserRole `json:"role,omitempty"` - Disabled bool `json:"disabled,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` -} - -type Vault struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Address string `json:"address,omitempty"` - Type VaultType `json:"type,omitempty"` - SupportedProducts []ProductType `json:"supportedProducts,omitempty"` - Network *Network `json:"network,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` - UpdatedAt Time `json:"updatedAt,omitempty"` -} - -type VaultsFilters struct { - Type *VaultType `json:"type,omitempty"` -} - -type VaultsInput struct { - Filter *VaultsFilters `json:"filter,omitempty"` -} - -type VerifyMercuryV03ContractInput struct { - ContractIDs []string `json:"contractIDs,omitempty"` -} - -type VerifyMercuryV03ContractPayload struct { - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` - Errors []Error `json:"errors,omitempty"` -} - -type Webhook struct { - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - EndpointURL string `json:"endpointURL,omitempty"` - SecretKey string `json:"secretKey,omitempty"` - Enabled bool `json:"enabled,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` - UpdatedAt Time `json:"updatedAt,omitempty"` -} - -type WebhookCall struct { - ID string `json:"id,omitempty"` - UUID string `json:"uuid,omitempty"` - Type string `json:"type,omitempty"` - State string `json:"state,omitempty"` - Payload string `json:"payload,omitempty"` - Attempts []*WebhookCallAttempt `json:"attempts,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` - DeliveredAt *Time `json:"deliveredAt,omitempty"` -} - -type WebhookCallAttempt struct { - ID string `json:"id,omitempty"` - StatusCode int `json:"statusCode,omitempty"` - Timestamp Time `json:"timestamp,omitempty"` -} - -type WorkflowRun struct { - ID string `json:"id,omitempty"` - WorkflowType WorkflowType `json:"workflowType,omitempty"` - Status WorkflowRunStatus `json:"status,omitempty"` - User *User `json:"user,omitempty"` - AccountAddress *string `json:"accountAddress,omitempty"` - Actions []*Action `json:"actions,omitempty"` - CreatedAt Time `json:"createdAt,omitempty"` - Name *string `json:"name,omitempty"` - DeletedAt *Time `json:"deletedAt,omitempty"` -} - -type WorkflowRunAndContract struct { - WorkflowRun *WorkflowRun `json:"workflowRun,omitempty"` - Contract *Contract `json:"contract,omitempty"` -} - -type WorkflowRunsFilters struct { - UserID *string `json:"userID,omitempty"` -} - -type WorkflowRunsInput struct { - Filter *WorkflowRunsFilters `json:"filter,omitempty"` -} - -type ActionRunStatus string - -const ( - ActionRunStatusPending ActionRunStatus = "PENDING" - ActionRunStatusInProgress ActionRunStatus = "IN_PROGRESS" - ActionRunStatusCompleted ActionRunStatus = "COMPLETED" - ActionRunStatusErrored ActionRunStatus = "ERRORED" -) - -var AllActionRunStatus = []ActionRunStatus{ - ActionRunStatusPending, - ActionRunStatusInProgress, - ActionRunStatusCompleted, - ActionRunStatusErrored, -} - -func (e ActionRunStatus) IsValid() bool { - switch e { - case ActionRunStatusPending, ActionRunStatusInProgress, ActionRunStatusCompleted, ActionRunStatusErrored: - return true - } - return false -} - -func (e ActionRunStatus) String() string { - return string(e) -} - -func (e *ActionRunStatus) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = ActionRunStatus(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid ActionRunStatus", str) - } - return nil -} - -func (e ActionRunStatus) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type ActionType string - -const ( - ActionTypeGeneric ActionType = "GENERIC" -) - -var AllActionType = []ActionType{ - ActionTypeGeneric, -} - -func (e ActionType) IsValid() bool { - switch e { - case ActionTypeGeneric: - return true - } - return false -} - -func (e ActionType) String() string { - return string(e) -} - -func (e *ActionType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = ActionType(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid ActionType", str) - } - return nil -} - -func (e ActionType) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type CCIPCommand string - -const ( - CCIPCommandSetConfig CCIPCommand = "SET_CONFIG" -) - -var AllCCIPCommand = []CCIPCommand{ - CCIPCommandSetConfig, -} - -func (e CCIPCommand) IsValid() bool { - switch e { - case CCIPCommandSetConfig: - return true - } - return false -} - -func (e CCIPCommand) String() string { - return string(e) -} - -func (e *CCIPCommand) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = CCIPCommand(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid CCIPCommand", str) - } - return nil -} - -func (e CCIPCommand) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type CCIPJobType string - -const ( - CCIPJobTypeCommit CCIPJobType = "COMMIT" - CCIPJobTypeExecute CCIPJobType = "EXECUTE" - CCIPJobTypeBootstrap CCIPJobType = "BOOTSTRAP" -) - -var AllCCIPJobType = []CCIPJobType{ - CCIPJobTypeCommit, - CCIPJobTypeExecute, - CCIPJobTypeBootstrap, -} - -func (e CCIPJobType) IsValid() bool { - switch e { - case CCIPJobTypeCommit, CCIPJobTypeExecute, CCIPJobTypeBootstrap: - return true - } - return false -} - -func (e CCIPJobType) String() string { - return string(e) -} - -func (e *CCIPJobType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = CCIPJobType(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid CCIPJobType", str) - } - return nil -} - -func (e CCIPJobType) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type CCIPLaneLegStatus string - -const ( - CCIPLaneLegStatusDraft CCIPLaneLegStatus = "DRAFT" - CCIPLaneLegStatusReady CCIPLaneLegStatus = "READY" -) - -var AllCCIPLaneLegStatus = []CCIPLaneLegStatus{ - CCIPLaneLegStatusDraft, - CCIPLaneLegStatusReady, -} - -func (e CCIPLaneLegStatus) IsValid() bool { - switch e { - case CCIPLaneLegStatusDraft, CCIPLaneLegStatusReady: - return true - } - return false -} - -func (e CCIPLaneLegStatus) String() string { - return string(e) -} - -func (e *CCIPLaneLegStatus) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = CCIPLaneLegStatus(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid CCIPLaneLegStatus", str) - } - return nil -} - -func (e CCIPLaneLegStatus) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type CCIPLaneLegTag string - -const ( - CCIPLaneLegTagMain CCIPLaneLegTag = "MAIN" - CCIPLaneLegTagProvisional CCIPLaneLegTag = "PROVISIONAL" - CCIPLaneLegTagDead CCIPLaneLegTag = "DEAD" -) - -var AllCCIPLaneLegTag = []CCIPLaneLegTag{ - CCIPLaneLegTagMain, - CCIPLaneLegTagProvisional, - CCIPLaneLegTagDead, -} - -func (e CCIPLaneLegTag) IsValid() bool { - switch e { - case CCIPLaneLegTagMain, CCIPLaneLegTagProvisional, CCIPLaneLegTagDead: - return true - } - return false -} - -func (e CCIPLaneLegTag) String() string { - return string(e) -} - -func (e *CCIPLaneLegTag) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = CCIPLaneLegTag(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid CCIPLaneLegTag", str) - } - return nil -} - -func (e CCIPLaneLegTag) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type ChainType string - -const ( - ChainTypeEvm ChainType = "EVM" - ChainTypeSolana ChainType = "SOLANA" - ChainTypeStarknet ChainType = "STARKNET" - ChainTypeAptos ChainType = "APTOS" - -) - -var AllChainType = []ChainType{ - ChainTypeEvm, - ChainTypeSolana, - ChainTypeStarknet, - ChainTypeAptos, -} - -func (e ChainType) IsValid() bool { - switch e { - case ChainTypeEvm, ChainTypeSolana, ChainTypeStarknet, ChainTypeAptos: - return true - } - return false -} - -func (e ChainType) String() string { - return string(e) -} - -func (e *ChainType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = ChainType(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid ChainType", str) - } - return nil -} - -func (e ChainType) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type ContractOwnerType string - -const ( - ContractOwnerTypeSystem ContractOwnerType = "SYSTEM" - ContractOwnerTypeExternal ContractOwnerType = "EXTERNAL" - ContractOwnerTypeVault ContractOwnerType = "VAULT" - ContractOwnerTypeNotOwnable ContractOwnerType = "NOT_OWNABLE" -) - -var AllContractOwnerType = []ContractOwnerType{ - ContractOwnerTypeSystem, - ContractOwnerTypeExternal, - ContractOwnerTypeVault, - ContractOwnerTypeNotOwnable, -} - -func (e ContractOwnerType) IsValid() bool { - switch e { - case ContractOwnerTypeSystem, ContractOwnerTypeExternal, ContractOwnerTypeVault, ContractOwnerTypeNotOwnable: - return true - } - return false -} - -func (e ContractOwnerType) String() string { - return string(e) -} - -func (e *ContractOwnerType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = ContractOwnerType(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid ContractOwnerType", str) - } - return nil -} - -func (e ContractOwnerType) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type ContractTag string - -const ( - ContractTagMain ContractTag = "MAIN" - ContractTagTest ContractTag = "TEST" - ContractTagUpgrade ContractTag = "UPGRADE" - ContractTagDead ContractTag = "DEAD" -) - -var AllContractTag = []ContractTag{ - ContractTagMain, - ContractTagTest, - ContractTagUpgrade, - ContractTagDead, -} - -func (e ContractTag) IsValid() bool { - switch e { - case ContractTagMain, ContractTagTest, ContractTagUpgrade, ContractTagDead: - return true - } - return false -} - -func (e ContractTag) String() string { - return string(e) -} - -func (e *ContractTag) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = ContractTag(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid ContractTag", str) - } - return nil -} - -func (e ContractTag) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type ContractType string - -const ( - ContractTypeOcr1 ContractType = "OCR1" - ContractTypeOcr2 ContractType = "OCR2" -) - -var AllContractType = []ContractType{ - ContractTypeOcr1, - ContractTypeOcr2, -} - -func (e ContractType) IsValid() bool { - switch e { - case ContractTypeOcr1, ContractTypeOcr2: - return true - } - return false -} - -func (e ContractType) String() string { - return string(e) -} - -func (e *ContractType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = ContractType(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid ContractType", str) - } - return nil -} - -func (e ContractType) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type DONExecutionType string - -const ( - DONExecutionTypeMercury DONExecutionType = "MERCURY" - DONExecutionTypeMercuryV03 DONExecutionType = "MERCURY_V03" - DONExecutionTypeAggregator DONExecutionType = "AGGREGATOR" - DONExecutionTypeCcipCommit DONExecutionType = "CCIP_COMMIT" - DONExecutionTypeCcipExecute DONExecutionType = "CCIP_EXECUTE" - DONExecutionTypeKeystoneWorkflow DONExecutionType = "KEYSTONE_WORKFLOW" -) - -var AllDONExecutionType = []DONExecutionType{ - DONExecutionTypeMercury, - DONExecutionTypeMercuryV03, - DONExecutionTypeAggregator, - DONExecutionTypeCcipCommit, - DONExecutionTypeCcipExecute, - DONExecutionTypeKeystoneWorkflow, -} - -func (e DONExecutionType) IsValid() bool { - switch e { - case DONExecutionTypeMercury, DONExecutionTypeMercuryV03, DONExecutionTypeAggregator, DONExecutionTypeCcipCommit, DONExecutionTypeCcipExecute, DONExecutionTypeKeystoneWorkflow: - return true - } - return false -} - -func (e DONExecutionType) String() string { - return string(e) -} - -func (e *DONExecutionType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = DONExecutionType(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid DONExecutionType", str) - } - return nil -} - -func (e DONExecutionType) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type DeploymentStatus string - -const ( - DeploymentStatusPending DeploymentStatus = "PENDING" - DeploymentStatusQueued DeploymentStatus = "QUEUED" - DeploymentStatusInProgress DeploymentStatus = "IN_PROGRESS" - DeploymentStatusCompleted DeploymentStatus = "COMPLETED" - DeploymentStatusErrored DeploymentStatus = "ERRORED" -) - -var AllDeploymentStatus = []DeploymentStatus{ - DeploymentStatusPending, - DeploymentStatusQueued, - DeploymentStatusInProgress, - DeploymentStatusCompleted, - DeploymentStatusErrored, -} - -func (e DeploymentStatus) IsValid() bool { - switch e { - case DeploymentStatusPending, DeploymentStatusQueued, DeploymentStatusInProgress, DeploymentStatusCompleted, DeploymentStatusErrored: - return true - } - return false -} - -func (e DeploymentStatus) String() string { - return string(e) -} - -func (e *DeploymentStatus) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = DeploymentStatus(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid DeploymentStatus", str) - } - return nil -} - -func (e DeploymentStatus) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type FeedStatus string - -const ( - FeedStatusDraft FeedStatus = "DRAFT" - FeedStatusReady FeedStatus = "READY" -) - -var AllFeedStatus = []FeedStatus{ - FeedStatusDraft, - FeedStatusReady, -} - -func (e FeedStatus) IsValid() bool { - switch e { - case FeedStatusDraft, FeedStatusReady: - return true - } - return false -} - -func (e FeedStatus) String() string { - return string(e) -} - -func (e *FeedStatus) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = FeedStatus(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid FeedStatus", str) - } - return nil -} - -func (e FeedStatus) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type JobProposalStatus string - -const ( - JobProposalStatusProposed JobProposalStatus = "PROPOSED" - JobProposalStatusApproved JobProposalStatus = "APPROVED" - JobProposalStatusRejected JobProposalStatus = "REJECTED" - JobProposalStatusAccepted JobProposalStatus = "ACCEPTED" - JobProposalStatusPending JobProposalStatus = "PENDING" -) - -var AllJobProposalStatus = []JobProposalStatus{ - JobProposalStatusProposed, - JobProposalStatusApproved, - JobProposalStatusRejected, - JobProposalStatusAccepted, - JobProposalStatusPending, -} - -func (e JobProposalStatus) IsValid() bool { - switch e { - case JobProposalStatusProposed, JobProposalStatusApproved, JobProposalStatusRejected, JobProposalStatusAccepted, JobProposalStatusPending: - return true - } - return false -} - -func (e JobProposalStatus) String() string { - return string(e) -} - -func (e *JobProposalStatus) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = JobProposalStatus(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid JobProposalStatus", str) - } - return nil -} - -func (e JobProposalStatus) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type JobStatus string - -const ( - JobStatusDraft JobStatus = "DRAFT" - JobStatusProposed JobStatus = "PROPOSED" - JobStatusApproved JobStatus = "APPROVED" - JobStatusRejected JobStatus = "REJECTED" - JobStatusCancelled JobStatus = "CANCELLED" - JobStatusDisabled JobStatus = "DISABLED" - JobStatusDeleted JobStatus = "DELETED" - JobStatusRevoked JobStatus = "REVOKED" -) - -var AllJobStatus = []JobStatus{ - JobStatusDraft, - JobStatusProposed, - JobStatusApproved, - JobStatusRejected, - JobStatusCancelled, - JobStatusDisabled, - JobStatusDeleted, - JobStatusRevoked, -} - -func (e JobStatus) IsValid() bool { - switch e { - case JobStatusDraft, JobStatusProposed, JobStatusApproved, JobStatusRejected, JobStatusCancelled, JobStatusDisabled, JobStatusDeleted, JobStatusRevoked: - return true - } - return false -} - -func (e JobStatus) String() string { - return string(e) -} - -func (e *JobStatus) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = JobStatus(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid JobStatus", str) - } - return nil -} - -func (e JobStatus) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type JobType string - -const ( - JobTypeOffchainreporting JobType = "OFFCHAINREPORTING" - JobTypeOffchainreporting2 JobType = "OFFCHAINREPORTING2" - JobTypeBootstrap JobType = "BOOTSTRAP" - JobTypeWorkflow JobType = "WORKFLOW" -) - -var AllJobType = []JobType{ - JobTypeOffchainreporting, - JobTypeOffchainreporting2, - JobTypeBootstrap, - JobTypeWorkflow, -} - -func (e JobType) IsValid() bool { - switch e { - case JobTypeOffchainreporting, JobTypeOffchainreporting2, JobTypeBootstrap, JobTypeWorkflow: - return true - } - return false -} - -func (e JobType) String() string { - return string(e) -} - -func (e *JobType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = JobType(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid JobType", str) - } - return nil -} - -func (e JobType) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type NetworkStackStatus string - -const ( - NetworkStackStatusReady NetworkStackStatus = "READY" - NetworkStackStatusInProgress NetworkStackStatus = "IN_PROGRESS" -) - -var AllNetworkStackStatus = []NetworkStackStatus{ - NetworkStackStatusReady, - NetworkStackStatusInProgress, -} - -func (e NetworkStackStatus) IsValid() bool { - switch e { - case NetworkStackStatusReady, NetworkStackStatusInProgress: - return true - } - return false -} - -func (e NetworkStackStatus) String() string { - return string(e) -} - -func (e *NetworkStackStatus) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = NetworkStackStatus(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid NetworkStackStatus", str) - } - return nil -} - -func (e NetworkStackStatus) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type NetworkStackType string - -const ( - NetworkStackTypeMain NetworkStackType = "MAIN" - NetworkStackTypeAdditional NetworkStackType = "ADDITIONAL" -) - -var AllNetworkStackType = []NetworkStackType{ - NetworkStackTypeMain, - NetworkStackTypeAdditional, -} - -func (e NetworkStackType) IsValid() bool { - switch e { - case NetworkStackTypeMain, NetworkStackTypeAdditional: - return true - } - return false -} - -func (e NetworkStackType) String() string { - return string(e) -} - -func (e *NetworkStackType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = NetworkStackType(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid NetworkStackType", str) - } - return nil -} - -func (e NetworkStackType) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type OCR2PluginType string - -const ( - OCR2PluginTypeMedian OCR2PluginType = "MEDIAN" - OCR2PluginTypeCcipCommit OCR2PluginType = "CCIP_COMMIT" - OCR2PluginTypeCcipExecute OCR2PluginType = "CCIP_EXECUTE" - OCR2PluginTypeCcipRebalancer OCR2PluginType = "CCIP_REBALANCER" - OCR2PluginTypeMercury OCR2PluginType = "MERCURY" -) - -var AllOCR2PluginType = []OCR2PluginType{ - OCR2PluginTypeMedian, - OCR2PluginTypeCcipCommit, - OCR2PluginTypeCcipExecute, - OCR2PluginTypeCcipRebalancer, - OCR2PluginTypeMercury, -} - -func (e OCR2PluginType) IsValid() bool { - switch e { - case OCR2PluginTypeMedian, OCR2PluginTypeCcipCommit, OCR2PluginTypeCcipExecute, OCR2PluginTypeCcipRebalancer, OCR2PluginTypeMercury: - return true - } - return false -} - -func (e OCR2PluginType) String() string { - return string(e) -} - -func (e *OCR2PluginType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = OCR2PluginType(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid OCR2PluginType", str) - } - return nil -} - -func (e OCR2PluginType) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type ProductType string - -const ( - ProductTypeDataFeeds ProductType = "DATA_FEEDS" - ProductTypeDataStreamsV02 ProductType = "DATA_STREAMS_V02" - ProductTypeDataStreamsV03 ProductType = "DATA_STREAMS_V03" - ProductTypeCcip ProductType = "CCIP" - ProductTypeWorkflow ProductType = "WORKFLOW" - ProductTypeOcr3Capability ProductType = "OCR3_CAPABILITY" -) - -var AllProductType = []ProductType{ - ProductTypeDataFeeds, - ProductTypeDataStreamsV02, - ProductTypeDataStreamsV03, - ProductTypeCcip, - ProductTypeWorkflow, - ProductTypeOcr3Capability, -} - -func (e ProductType) IsValid() bool { - switch e { - case ProductTypeDataFeeds, ProductTypeDataStreamsV02, ProductTypeDataStreamsV03, ProductTypeCcip, ProductTypeWorkflow, ProductTypeOcr3Capability: - return true - } - return false -} - -func (e ProductType) String() string { - return string(e) -} - -func (e *ProductType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = ProductType(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid ProductType", str) - } - return nil -} - -func (e ProductType) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type ReportSchemaVersion string - -const ( - ReportSchemaVersionBasic ReportSchemaVersion = "BASIC" - ReportSchemaVersionPremium ReportSchemaVersion = "PREMIUM" - ReportSchemaVersionBlockBased ReportSchemaVersion = "BLOCK_BASED" -) - -var AllReportSchemaVersion = []ReportSchemaVersion{ - ReportSchemaVersionBasic, - ReportSchemaVersionPremium, - ReportSchemaVersionBlockBased, -} - -func (e ReportSchemaVersion) IsValid() bool { - switch e { - case ReportSchemaVersionBasic, ReportSchemaVersionPremium, ReportSchemaVersionBlockBased: - return true - } - return false -} - -func (e ReportSchemaVersion) String() string { - return string(e) -} - -func (e *ReportSchemaVersion) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = ReportSchemaVersion(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid ReportSchemaVersion", str) - } - return nil -} - -func (e ReportSchemaVersion) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type SelectorOp string - -const ( - SelectorOpEq SelectorOp = "EQ" - SelectorOpNotEq SelectorOp = "NOT_EQ" - SelectorOpIn SelectorOp = "IN" - SelectorOpNotIn SelectorOp = "NOT_IN" - SelectorOpExist SelectorOp = "EXIST" - SelectorOpNotExist SelectorOp = "NOT_EXIST" -) - -var AllSelectorOp = []SelectorOp{ - SelectorOpEq, - SelectorOpNotEq, - SelectorOpIn, - SelectorOpNotIn, - SelectorOpExist, - SelectorOpNotExist, -} - -func (e SelectorOp) IsValid() bool { - switch e { - case SelectorOpEq, SelectorOpNotEq, SelectorOpIn, SelectorOpNotIn, SelectorOpExist, SelectorOpNotExist: - return true - } - return false -} - -func (e SelectorOp) String() string { - return string(e) -} - -func (e *SelectorOp) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = SelectorOp(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid SelectorOp", str) - } - return nil -} - -func (e SelectorOp) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type TaskRunStatus string - -const ( - TaskRunStatusInProgress TaskRunStatus = "IN_PROGRESS" - TaskRunStatusCompleted TaskRunStatus = "COMPLETED" - TaskRunStatusErrored TaskRunStatus = "ERRORED" -) - -var AllTaskRunStatus = []TaskRunStatus{ - TaskRunStatusInProgress, - TaskRunStatusCompleted, - TaskRunStatusErrored, -} - -func (e TaskRunStatus) IsValid() bool { - switch e { - case TaskRunStatusInProgress, TaskRunStatusCompleted, TaskRunStatusErrored: - return true - } - return false -} - -func (e TaskRunStatus) String() string { - return string(e) -} - -func (e *TaskRunStatus) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = TaskRunStatus(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid TaskRunStatus", str) - } - return nil -} - -func (e TaskRunStatus) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type TokenPoolType string - -const ( - TokenPoolTypeLockRelease TokenPoolType = "LOCK_RELEASE" - TokenPoolTypeLockReleaseAndProxy TokenPoolType = "LOCK_RELEASE_AND_PROXY" - TokenPoolTypeBurnMint TokenPoolType = "BURN_MINT" - TokenPoolTypeBurnMintAndProxy TokenPoolType = "BURN_MINT_AND_PROXY" - TokenPoolTypeBurnFromMint TokenPoolType = "BURN_FROM_MINT" - TokenPoolTypeBurnWithFromMint TokenPoolType = "BURN_WITH_FROM_MINT" - TokenPoolTypeBurnWithFromMintAndProxy TokenPoolType = "BURN_WITH_FROM_MINT_AND_PROXY" - TokenPoolTypeUsdc TokenPoolType = "USDC" - TokenPoolTypeFeeTokenOnly TokenPoolType = "FEE_TOKEN_ONLY" -) - -var AllTokenPoolType = []TokenPoolType{ - TokenPoolTypeLockRelease, - TokenPoolTypeLockReleaseAndProxy, - TokenPoolTypeBurnMint, - TokenPoolTypeBurnMintAndProxy, - TokenPoolTypeBurnFromMint, - TokenPoolTypeBurnWithFromMint, - TokenPoolTypeBurnWithFromMintAndProxy, - TokenPoolTypeUsdc, - TokenPoolTypeFeeTokenOnly, -} - -func (e TokenPoolType) IsValid() bool { - switch e { - case TokenPoolTypeLockRelease, TokenPoolTypeLockReleaseAndProxy, TokenPoolTypeBurnMint, TokenPoolTypeBurnMintAndProxy, TokenPoolTypeBurnFromMint, TokenPoolTypeBurnWithFromMint, TokenPoolTypeBurnWithFromMintAndProxy, TokenPoolTypeUsdc, TokenPoolTypeFeeTokenOnly: - return true - } - return false -} - -func (e TokenPoolType) String() string { - return string(e) -} - -func (e *TokenPoolType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = TokenPoolType(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid TokenPoolType", str) - } - return nil -} - -func (e TokenPoolType) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type TokenPriceType string - -const ( - TokenPriceTypeFixed TokenPriceType = "FIXED" - TokenPriceTypeFeed TokenPriceType = "FEED" -) - -var AllTokenPriceType = []TokenPriceType{ - TokenPriceTypeFixed, - TokenPriceTypeFeed, -} - -func (e TokenPriceType) IsValid() bool { - switch e { - case TokenPriceTypeFixed, TokenPriceTypeFeed: - return true - } - return false -} - -func (e TokenPriceType) String() string { - return string(e) -} - -func (e *TokenPriceType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = TokenPriceType(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid TokenPriceType", str) - } - return nil -} - -func (e TokenPriceType) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type TransferOwnershipStatus string - -const ( - TransferOwnershipStatusNone TransferOwnershipStatus = "NONE" - TransferOwnershipStatusProcessingTransaction TransferOwnershipStatus = "PROCESSING_TRANSACTION" - TransferOwnershipStatusAwaitingConfirmation TransferOwnershipStatus = "AWAITING_CONFIRMATION" - TransferOwnershipStatusError TransferOwnershipStatus = "ERROR" -) - -var AllTransferOwnershipStatus = []TransferOwnershipStatus{ - TransferOwnershipStatusNone, - TransferOwnershipStatusProcessingTransaction, - TransferOwnershipStatusAwaitingConfirmation, - TransferOwnershipStatusError, -} - -func (e TransferOwnershipStatus) IsValid() bool { - switch e { - case TransferOwnershipStatusNone, TransferOwnershipStatusProcessingTransaction, TransferOwnershipStatusAwaitingConfirmation, TransferOwnershipStatusError: - return true - } - return false -} - -func (e TransferOwnershipStatus) String() string { - return string(e) -} - -func (e *TransferOwnershipStatus) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = TransferOwnershipStatus(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid TransferOwnershipStatus", str) - } - return nil -} - -func (e TransferOwnershipStatus) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type UserRole string - -const ( - UserRoleViewer UserRole = "VIEWER" - UserRoleOps UserRole = "OPS" - UserRoleMaintainer UserRole = "MAINTAINER" - UserRoleAdmin UserRole = "ADMIN" - UserRoleFoundation UserRole = "FOUNDATION" - UserRoleDataProvider UserRole = "DATA_PROVIDER" - UserRoleCcipValidator UserRole = "CCIP_VALIDATOR" - UserRoleDataStreamsOps UserRole = "DATA_STREAMS_OPS" -) - -var AllUserRole = []UserRole{ - UserRoleViewer, - UserRoleOps, - UserRoleMaintainer, - UserRoleAdmin, - UserRoleFoundation, - UserRoleDataProvider, - UserRoleCcipValidator, - UserRoleDataStreamsOps, -} - -func (e UserRole) IsValid() bool { - switch e { - case UserRoleViewer, UserRoleOps, UserRoleMaintainer, UserRoleAdmin, UserRoleFoundation, UserRoleDataProvider, UserRoleCcipValidator, UserRoleDataStreamsOps: - return true - } - return false -} - -func (e UserRole) String() string { - return string(e) -} - -func (e *UserRole) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = UserRole(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid UserRole", str) - } - return nil -} - -func (e UserRole) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type VaultType string - -const ( - VaultTypeEoa VaultType = "EOA" - VaultTypeSafe VaultType = "SAFE" - VaultTypeTimelock VaultType = "TIMELOCK" -) - -var AllVaultType = []VaultType{ - VaultTypeEoa, - VaultTypeSafe, - VaultTypeTimelock, -} - -func (e VaultType) IsValid() bool { - switch e { - case VaultTypeEoa, VaultTypeSafe, VaultTypeTimelock: - return true - } - return false -} - -func (e VaultType) String() string { - return string(e) -} - -func (e *VaultType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = VaultType(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid VaultType", str) - } - return nil -} - -func (e VaultType) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type VerificationStatus string - -const ( - VerificationStatusUnknown VerificationStatus = "UNKNOWN" - VerificationStatusSuccess VerificationStatus = "SUCCESS" - VerificationStatusPending VerificationStatus = "PENDING" - VerificationStatusError VerificationStatus = "ERROR" -) - -var AllVerificationStatus = []VerificationStatus{ - VerificationStatusUnknown, - VerificationStatusSuccess, - VerificationStatusPending, - VerificationStatusError, -} - -func (e VerificationStatus) IsValid() bool { - switch e { - case VerificationStatusUnknown, VerificationStatusSuccess, VerificationStatusPending, VerificationStatusError: - return true - } - return false -} - -func (e VerificationStatus) String() string { - return string(e) -} - -func (e *VerificationStatus) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = VerificationStatus(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid VerificationStatus", str) - } - return nil -} - -func (e VerificationStatus) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type WebhookCallState string - -const ( - WebhookCallStatePending WebhookCallState = "PENDING" - WebhookCallStateSuccess WebhookCallState = "SUCCESS" - WebhookCallStateError WebhookCallState = "ERROR" - WebhookCallStateFailed WebhookCallState = "FAILED" -) - -var AllWebhookCallState = []WebhookCallState{ - WebhookCallStatePending, - WebhookCallStateSuccess, - WebhookCallStateError, - WebhookCallStateFailed, -} - -func (e WebhookCallState) IsValid() bool { - switch e { - case WebhookCallStatePending, WebhookCallStateSuccess, WebhookCallStateError, WebhookCallStateFailed: - return true - } - return false -} - -func (e WebhookCallState) String() string { - return string(e) -} - -func (e *WebhookCallState) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = WebhookCallState(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid WebhookCallState", str) - } - return nil -} - -func (e WebhookCallState) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type WorkflowRunStatus string - -const ( - WorkflowRunStatusPending WorkflowRunStatus = "PENDING" - WorkflowRunStatusInProgress WorkflowRunStatus = "IN_PROGRESS" - WorkflowRunStatusCompleted WorkflowRunStatus = "COMPLETED" - WorkflowRunStatusErrored WorkflowRunStatus = "ERRORED" -) - -var AllWorkflowRunStatus = []WorkflowRunStatus{ - WorkflowRunStatusPending, - WorkflowRunStatusInProgress, - WorkflowRunStatusCompleted, - WorkflowRunStatusErrored, -} - -func (e WorkflowRunStatus) IsValid() bool { - switch e { - case WorkflowRunStatusPending, WorkflowRunStatusInProgress, WorkflowRunStatusCompleted, WorkflowRunStatusErrored: - return true - } - return false -} - -func (e WorkflowRunStatus) String() string { - return string(e) -} - -func (e *WorkflowRunStatus) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = WorkflowRunStatus(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid WorkflowRunStatus", str) - } - return nil -} - -func (e WorkflowRunStatus) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} - -type WorkflowType string - -const ( - WorkflowTypeGeneric WorkflowType = "GENERIC" -) - -var AllWorkflowType = []WorkflowType{ - WorkflowTypeGeneric, -} - -func (e WorkflowType) IsValid() bool { - switch e { - case WorkflowTypeGeneric: - return true - } - return false -} - -func (e WorkflowType) String() string { - return string(e) -} - -func (e *WorkflowType) UnmarshalGQL(v interface{}) error { - str, ok := v.(string) - if !ok { - return fmt.Errorf("enums must be strings") - } - - *e = WorkflowType(str) - if !e.IsValid() { - return fmt.Errorf("%s is not a valid WorkflowType", str) - } - return nil -} - -func (e WorkflowType) MarshalGQL(w io.Writer) { - fmt.Fprint(w, strconv.Quote(e.String())) -} diff --git a/deployment/environment/clo/offchain_client_impl.go b/deployment/environment/clo/offchain_client_impl.go deleted file mode 100644 index 2046a32f810..00000000000 --- a/deployment/environment/clo/offchain_client_impl.go +++ /dev/null @@ -1,271 +0,0 @@ -package clo - -import ( - "context" - "fmt" - "slices" - "strings" - - "go.uber.org/zap" - "google.golang.org/grpc" - - "github.com/smartcontractkit/chainlink-common/pkg/logger" - 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" -) - -type JobClient struct { - NodeOperators []*models.NodeOperator `json:"nodeOperators"` - nodesByID map[string]*models.Node - lggr logger.Logger -} - -func (j JobClient) BatchProposeJob(ctx context.Context, in *jobv1.BatchProposeJobRequest, opts ...grpc.CallOption) (*jobv1.BatchProposeJobResponse, error) { - //TODO implement me - panic("implement me") -} - -func (j JobClient) UpdateJob(ctx context.Context, in *jobv1.UpdateJobRequest, opts ...grpc.CallOption) (*jobv1.UpdateJobResponse, error) { - //TODO CCIP-3108 implement me - panic("implement me") -} - -func (j JobClient) DisableNode(ctx context.Context, in *nodev1.DisableNodeRequest, opts ...grpc.CallOption) (*nodev1.DisableNodeResponse, error) { - //TODO CCIP-3108 implement me - panic("implement me") -} - -func (j JobClient) EnableNode(ctx context.Context, in *nodev1.EnableNodeRequest, opts ...grpc.CallOption) (*nodev1.EnableNodeResponse, error) { - //TODO CCIP-3108 implement me - panic("implement me") -} - -func (j JobClient) RegisterNode(ctx context.Context, in *nodev1.RegisterNodeRequest, opts ...grpc.CallOption) (*nodev1.RegisterNodeResponse, error) { - //TODO implement me - panic("implement me") -} - -func (j JobClient) UpdateNode(ctx context.Context, in *nodev1.UpdateNodeRequest, opts ...grpc.CallOption) (*nodev1.UpdateNodeResponse, error) { - //TODO CCIP-3108 implement me - panic("implement me") -} - -func (j JobClient) GetKeypair(ctx context.Context, in *csav1.GetKeypairRequest, opts ...grpc.CallOption) (*csav1.GetKeypairResponse, error) { - //TODO implement me - panic("implement me") -} - -func (j JobClient) ListKeypairs(ctx context.Context, in *csav1.ListKeypairsRequest, opts ...grpc.CallOption) (*csav1.ListKeypairsResponse, error) { - //TODO CCIP-3108 implement me - panic("implement me") -} - -func (j JobClient) GetNode(ctx context.Context, in *nodev1.GetNodeRequest, opts ...grpc.CallOption) (*nodev1.GetNodeResponse, error) { - //TODO CCIP-3108 implement me - panic("implement me") -} - -func (j JobClient) ListNodes(ctx context.Context, in *nodev1.ListNodesRequest, opts ...grpc.CallOption) (*nodev1.ListNodesResponse, error) { - include := func(node *nodev1.Node) bool { - if in.Filter == nil { - return true - } - 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") - } - } - return true - } - var nodes []*nodev1.Node - for _, nop := range j.NodeOperators { - for _, n := range nop.Nodes { - 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) { - - resp := &nodev1.ListNodeChainConfigsResponse{ - ChainConfigs: make([]*nodev1.ChainConfig, 0), - } - // no filter, return all - if in.Filter == nil || len(in.Filter.NodeIds) == 0 { - for _, n := range j.nodesByID { - ccfg := cloNodeToChainConfigs(n) - resp.ChainConfigs = append(resp.ChainConfigs, ccfg...) - } - } else { - for _, want := range in.Filter.NodeIds { - n, ok := j.nodesByID[want] - if !ok { - j.lggr.Warn("node not found", zap.String("node_id", want)) - continue - } - ccfg := cloNodeToChainConfigs(n) - resp.ChainConfigs = append(resp.ChainConfigs, ccfg...) - } - } - return resp, nil - -} - -func (j JobClient) GetJob(ctx context.Context, in *jobv1.GetJobRequest, opts ...grpc.CallOption) (*jobv1.GetJobResponse, error) { - //TODO CCIP-3108 implement me - panic("implement me") -} - -func (j JobClient) GetProposal(ctx context.Context, in *jobv1.GetProposalRequest, opts ...grpc.CallOption) (*jobv1.GetProposalResponse, error) { - //TODO CCIP-3108 implement me - panic("implement me") -} - -func (j JobClient) ListJobs(ctx context.Context, in *jobv1.ListJobsRequest, opts ...grpc.CallOption) (*jobv1.ListJobsResponse, error) { - //TODO CCIP-3108 implement me - panic("implement me") -} - -func (j JobClient) ListProposals(ctx context.Context, in *jobv1.ListProposalsRequest, opts ...grpc.CallOption) (*jobv1.ListProposalsResponse, error) { - //TODO CCIP-3108 implement me - panic("implement me") -} - -func (j JobClient) ProposeJob(ctx context.Context, in *jobv1.ProposeJobRequest, opts ...grpc.CallOption) (*jobv1.ProposeJobResponse, error) { - panic("implement me") - -} - -func (j JobClient) RevokeJob(ctx context.Context, in *jobv1.RevokeJobRequest, opts ...grpc.CallOption) (*jobv1.RevokeJobResponse, error) { - //TODO CCIP-3108 implement me - panic("implement me") -} - -func (j JobClient) DeleteJob(ctx context.Context, in *jobv1.DeleteJobRequest, opts ...grpc.CallOption) (*jobv1.DeleteJobResponse, error) { - //TODO CCIP-3108 implement me - panic("implement me") -} - -type GetNodeOperatorsResponse struct { - NodeOperators []*models.NodeOperator `json:"nodeOperators"` -} - -type JobClientConfig struct { - Nops []*models.NodeOperator -} - -func NewJobClient(lggr logger.Logger, cfg JobClientConfig) *JobClient { - - c := &JobClient{ - NodeOperators: cfg.Nops, - nodesByID: make(map[string]*models.Node), - lggr: lggr, - } - for _, nop := range c.NodeOperators { - for _, n := range nop.Nodes { - node := n - c.nodesByID[n.ID] = node // maybe should use the public key instead? - } - } - return c -} - -func cloNodeToChainConfigs(n *models.Node) []*nodev1.ChainConfig { - out := make([]*nodev1.ChainConfig, 0) - for _, ccfg := range n.ChainConfigs { - out = append(out, cloChainCfgToJDChainCfg(ccfg)) - } - return out -} - -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: ctype, - }, - AccountAddress: ccfg.AccountAddress, - AdminAddress: ccfg.AdminAddress, - // only care about ocr2 for now - Ocr2Config: &nodev1.OCR2Config{ - Enabled: ccfg.Ocr2Config.Enabled, - IsBootstrap: ccfg.Ocr2Config.IsBootstrap, - P2PKeyBundle: &nodev1.OCR2Config_P2PKeyBundle{ - PeerId: ccfg.Ocr2Config.P2pKeyBundle.PeerID, - PublicKey: ccfg.Ocr2Config.P2pKeyBundle.PublicKey, - }, - OcrKeyBundle: &nodev1.OCR2Config_OCRKeyBundle{ - BundleId: ccfg.Ocr2Config.OcrKeyBundle.BundleID, - ConfigPublicKey: ccfg.Ocr2Config.OcrKeyBundle.ConfigPublicKey, - OffchainPublicKey: ccfg.Ocr2Config.OcrKeyBundle.OffchainPublicKey, - OnchainSigningAddress: ccfg.Ocr2Config.OcrKeyBundle.OnchainSigningAddress, - }, - // TODO: the clo cli does not serialize this field, so it will always be nil - //Multiaddr: *ccfg.Ocr2Config.Multiaddr, - //ForwarderAddress: ccfg.Ocr2Config.ForwarderAddress, - }, - } -} diff --git a/deployment/environment/clo/offchain_client_impl_test.go b/deployment/environment/clo/offchain_client_impl_test.go deleted file mode 100644 index f2d6fcf6f41..00000000000 --- a/deployment/environment/clo/offchain_client_impl_test.go +++ /dev/null @@ -1,677 +0,0 @@ -package clo_test - -import ( - "context" - "encoding/json" - "reflect" - "testing" - - "github.com/test-go/testify/require" - "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 = ` -[ - { - "id": "67", - "name": "Chainlink Keystone Node Operator 9", - "nodes": [ - { - "id": "780", - "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" - ] - } - ], - "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, - "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 { - t.Helper() - var out []*models.NodeOperator - err := json.Unmarshal([]byte(testNops), &out) - require.NoError(t, err) - require.Len(t, out, 3, "wrong number of nops") - return out -} -func TestJobClient_ListNodes(t *testing.T) { - lggr := logger.TestLogger(t) - nops := parseTestNops(t) - - type fields struct { - NodeOperators []*models.NodeOperator - RemapNodeIDsToPeerIDs bool - } - type args struct { - ctx context.Context - in *nodev1.ListNodesRequest - opts []grpc.CallOption - } - tests := []struct { - name string - fields fields - args args - want *nodev1.ListNodesResponse - wantErr bool - }{ - { - name: "empty", - fields: fields{ - NodeOperators: make([]*models.NodeOperator, 0), - }, - args: args{ - ctx: context.Background(), - in: &nodev1.ListNodesRequest{}, - }, - want: &nodev1.ListNodesResponse{}, - }, - { - name: "one node from one nop", - fields: fields{ - NodeOperators: nops[0:1], - }, - args: args{ - ctx: context.Background(), - in: &nodev1.ListNodesRequest{}, - }, - want: &nodev1.ListNodesResponse{ - Nodes: []*nodev1.Node{ - { - Id: "780", - Name: "Chainlink Sepolia Prod Keystone One 9", - PublicKey: "412dc6fe48ea4e34baaa77da2e3b032d39b938597b6f3d61fe7ed183a827a431", - IsConnected: true, - Labels: []*ptypes.Label{ - { - Key: "p2p_id", - Value: &p2pid_1, - }, - }, - }, - }, - }, - }, - { - name: "two nops each with one node", - fields: fields{ - NodeOperators: nops[0:2], - }, - args: args{ - ctx: context.Background(), - in: &nodev1.ListNodesRequest{}, - }, - want: &nodev1.ListNodesResponse{ - Nodes: []*nodev1.Node{ - { - Id: "780", - 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, - }, - }, - }, - }, - }, - }, - { - name: "two nodes from one nop", - fields: fields{ - NodeOperators: nops[2:3], - }, - args: args{ - ctx: context.Background(), - in: &nodev1.ListNodesRequest{}, - }, - want: &nodev1.ListNodesResponse{ - Nodes: []*nodev1.Node{ - { - Id: "999", - 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, - }, - }, - }, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - 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 { - t.Errorf("JobClient.ListNodes() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("JobClient.ListNodes() = %v, want %v", got, tt.want) - } - }) - } -} - -var testNopsWithChainConfigs = ` -[ - { - "id": "67", - "keys": [ - "keystone-09" - ], - "name": "Chainlink Keystone Node Operator 9", - "metadata": { - "nodeCount": 1, - "jobCount": 4 - }, - "nodes": [ - { - "id": "780", - "name": "Chainlink Sepolia Prod Keystone One 9", - "publicKey": "412dc6fe48ea4e34baaa77da2e3b032d39b938597b6f3d61fe7ed183a827a431", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xbA8E21dFaa0501fCD43146d0b5F21c2B8E0eEdfB", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE8TxNr5dM4U", - "publicKey": "147d5cc651819b093cd2fdff9760f0f0f77b7ef7798d9e24fc6a350b7300e5d9" - }, - "ocrKeyBundle": { - "bundleID": "1c28e76d180d1ed1524e61845fa58a384415de7e51017edf1f8c553e28357772", - "configPublicKey": "09fced0207611ed618bf0759ab128d9797e15b18e46436be1a56a91e4043ec0e", - "offchainPublicKey": "c805572b813a072067eab2087ddbee8aa719090e12890b15c01094f0d3f74a5f", - "onchainSigningAddress": "679296b7c1eb4948efcc87efc550940a182e610c" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x0b04cE574E80Da73191Ec141c0016a54A6404056", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE8TxNr5dM4U", - "publicKey": "147d5cc651819b093cd2fdff9760f0f0f77b7ef7798d9e24fc6a350b7300e5d9" - }, - "ocrKeyBundle": { - "bundleID": "1c28e76d180d1ed1524e61845fa58a384415de7e51017edf1f8c553e28357772", - "configPublicKey": "09fced0207611ed618bf0759ab128d9797e15b18e46436be1a56a91e4043ec0e", - "offchainPublicKey": "c805572b813a072067eab2087ddbee8aa719090e12890b15c01094f0d3f74a5f", - "onchainSigningAddress": "679296b7c1eb4948efcc87efc550940a182e610c" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T19:00:07.113658Z" - }, - { - "id": "68", - "keys": [ - "keystone-08" - ], - "name": "Chainlink Keystone Node Operator 8", - "metadata": { - "nodeCount": 1, - "jobCount": 4 - }, - "nodes": [ - { - "id": "781", - "name": "Chainlink Sepolia Prod Keystone One 8", - "publicKey": "1141dd1e46797ced9b0fbad49115f18507f6f6e6e3cc86e7e5ba169e58645adc", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xEa4bC3638660D78Da56f39f6680dCDD0cEAaD2c6", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWAUagqMycsro27kFznSQRHbhfCBLx8nKD4ptTiUGDe38c", - "publicKey": "09ca39cd924653c72fbb0e458b629c3efebdad3e29e7cd0b5760754d919ed829" - }, - "ocrKeyBundle": { - "bundleID": "be0d639de3ae3cbeaa31ca369514f748ba1d271145cba6796bcc12aace2f64c3", - "configPublicKey": "e3d4d7a7372a3b1110db0290ab3649eb5fbb0daf6cf3ae02cfe5f367700d9264", - "offchainPublicKey": "ad08c2a5878cada53521f4e2bb449f191ccca7899246721a0deeea19f7b83f70", - "onchainSigningAddress": "8c2aa1e6fad88a6006dfb116eb866cbad2910314" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x31B179dcF8f9036C30f04bE578793e51bF14A39E", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWAUagqMycsro27kFznSQRHbhfCBLx8nKD4ptTiUGDe38c", - "publicKey": "09ca39cd924653c72fbb0e458b629c3efebdad3e29e7cd0b5760754d919ed829" - }, - "ocrKeyBundle": { - "bundleID": "be0d639de3ae3cbeaa31ca369514f748ba1d271145cba6796bcc12aace2f64c3", - "configPublicKey": "e3d4d7a7372a3b1110db0290ab3649eb5fbb0daf6cf3ae02cfe5f367700d9264", - "offchainPublicKey": "ad08c2a5878cada53521f4e2bb449f191ccca7899246721a0deeea19f7b83f70", - "onchainSigningAddress": "8c2aa1e6fad88a6006dfb116eb866cbad2910314" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:26:37.622463Z" - } -]` - -func TestJobClient_ListNodeChainConfigs(t *testing.T) { - nops := parseTestNopsWithChainConfigs(t) - lggr := logger.TestLogger(t) - type fields struct { - NodeOperators []*models.NodeOperator - } - type args struct { - ctx context.Context - in *nodev1.ListNodeChainConfigsRequest - opts []grpc.CallOption - } - tests := []struct { - name string - fields fields - args args - want *nodev1.ListNodeChainConfigsResponse - wantErr bool - }{ - { - name: "empty", - fields: fields{ - NodeOperators: make([]*models.NodeOperator, 0), - }, - args: args{ - ctx: context.Background(), - in: &nodev1.ListNodeChainConfigsRequest{}, - }, - want: &nodev1.ListNodeChainConfigsResponse{ - ChainConfigs: make([]*nodev1.ChainConfig, 0), - }, - }, - - { - name: "no matching nodes", - fields: fields{ - NodeOperators: nops, - }, - args: args{ - ctx: context.Background(), - in: &nodev1.ListNodeChainConfigsRequest{ - Filter: &nodev1.ListNodeChainConfigsRequest_Filter{ - NodeIds: []string{"not-a-node-id"}, - }, - }, - }, - want: &nodev1.ListNodeChainConfigsResponse{ - ChainConfigs: make([]*nodev1.ChainConfig, 0), - }, - }, - - { - name: "one nop with one node that has two chain configs", - fields: fields{ - NodeOperators: nops[0:1], - }, - args: args{ - ctx: context.Background(), - in: &nodev1.ListNodeChainConfigsRequest{}, - }, - want: &nodev1.ListNodeChainConfigsResponse{ - ChainConfigs: []*nodev1.ChainConfig{ - { - Chain: &nodev1.Chain{ - Id: "421614", - Type: nodev1.ChainType_CHAIN_TYPE_EVM, - }, - AccountAddress: "0xbA8E21dFaa0501fCD43146d0b5F21c2B8E0eEdfB", - AdminAddress: "0x0000000000000000000000000000000000000000", - Ocr2Config: &nodev1.OCR2Config{ - Enabled: true, - P2PKeyBundle: &nodev1.OCR2Config_P2PKeyBundle{ - PeerId: "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE8TxNr5dM4U", - PublicKey: "147d5cc651819b093cd2fdff9760f0f0f77b7ef7798d9e24fc6a350b7300e5d9", - }, - OcrKeyBundle: &nodev1.OCR2Config_OCRKeyBundle{ - BundleId: "1c28e76d180d1ed1524e61845fa58a384415de7e51017edf1f8c553e28357772", - ConfigPublicKey: "09fced0207611ed618bf0759ab128d9797e15b18e46436be1a56a91e4043ec0e", - OffchainPublicKey: "c805572b813a072067eab2087ddbee8aa719090e12890b15c01094f0d3f74a5f", - OnchainSigningAddress: "679296b7c1eb4948efcc87efc550940a182e610c", - }, - }, - }, - { - Chain: &nodev1.Chain{ - Id: "11155111", - Type: nodev1.ChainType_CHAIN_TYPE_EVM, - }, - AccountAddress: "0x0b04cE574E80Da73191Ec141c0016a54A6404056", - AdminAddress: "0x0000000000000000000000000000000000000000", - Ocr2Config: &nodev1.OCR2Config{ - Enabled: true, - P2PKeyBundle: &nodev1.OCR2Config_P2PKeyBundle{ - PeerId: "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE8TxNr5dM4U", - PublicKey: "147d5cc651819b093cd2fdff9760f0f0f77b7ef7798d9e24fc6a350b7300e5d9", - }, - OcrKeyBundle: &nodev1.OCR2Config_OCRKeyBundle{ - BundleId: "1c28e76d180d1ed1524e61845fa58a384415de7e51017edf1f8c553e28357772", - ConfigPublicKey: "09fced0207611ed618bf0759ab128d9797e15b18e46436be1a56a91e4043ec0e", - OffchainPublicKey: "c805572b813a072067eab2087ddbee8aa719090e12890b15c01094f0d3f74a5f", - OnchainSigningAddress: "679296b7c1eb4948efcc87efc550940a182e610c", - }, - }, - }, - }, - }, - }, - - { - name: "one nop with one node that has two chain configs matching the filter", - fields: fields{ - NodeOperators: nops, - }, - args: args{ - ctx: context.Background(), - in: &nodev1.ListNodeChainConfigsRequest{ - Filter: &nodev1.ListNodeChainConfigsRequest_Filter{ - NodeIds: []string{"780"}, - }, - }, - }, - want: &nodev1.ListNodeChainConfigsResponse{ - ChainConfigs: []*nodev1.ChainConfig{ - { - Chain: &nodev1.Chain{ - Id: "421614", - Type: nodev1.ChainType_CHAIN_TYPE_EVM, - }, - AccountAddress: "0xbA8E21dFaa0501fCD43146d0b5F21c2B8E0eEdfB", - AdminAddress: "0x0000000000000000000000000000000000000000", - Ocr2Config: &nodev1.OCR2Config{ - Enabled: true, - P2PKeyBundle: &nodev1.OCR2Config_P2PKeyBundle{ - PeerId: "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE8TxNr5dM4U", - PublicKey: "147d5cc651819b093cd2fdff9760f0f0f77b7ef7798d9e24fc6a350b7300e5d9", - }, - OcrKeyBundle: &nodev1.OCR2Config_OCRKeyBundle{ - BundleId: "1c28e76d180d1ed1524e61845fa58a384415de7e51017edf1f8c553e28357772", - ConfigPublicKey: "09fced0207611ed618bf0759ab128d9797e15b18e46436be1a56a91e4043ec0e", - OffchainPublicKey: "c805572b813a072067eab2087ddbee8aa719090e12890b15c01094f0d3f74a5f", - OnchainSigningAddress: "679296b7c1eb4948efcc87efc550940a182e610c", - }, - }, - }, - { - Chain: &nodev1.Chain{ - Id: "11155111", - Type: nodev1.ChainType_CHAIN_TYPE_EVM, - }, - AccountAddress: "0x0b04cE574E80Da73191Ec141c0016a54A6404056", - AdminAddress: "0x0000000000000000000000000000000000000000", - Ocr2Config: &nodev1.OCR2Config{ - Enabled: true, - P2PKeyBundle: &nodev1.OCR2Config_P2PKeyBundle{ - PeerId: "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE8TxNr5dM4U", - PublicKey: "147d5cc651819b093cd2fdff9760f0f0f77b7ef7798d9e24fc6a350b7300e5d9", - }, - OcrKeyBundle: &nodev1.OCR2Config_OCRKeyBundle{ - BundleId: "1c28e76d180d1ed1524e61845fa58a384415de7e51017edf1f8c553e28357772", - ConfigPublicKey: "09fced0207611ed618bf0759ab128d9797e15b18e46436be1a56a91e4043ec0e", - OffchainPublicKey: "c805572b813a072067eab2087ddbee8aa719090e12890b15c01094f0d3f74a5f", - OnchainSigningAddress: "679296b7c1eb4948efcc87efc550940a182e610c", - }, - }, - }, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - 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 { - t.Errorf("JobClient.ListNodeChainConfigs() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("JobClient.ListNodeChainConfigs() = %v, want %v", got, tt.want) - } - }) - } -} - -func parseTestNopsWithChainConfigs(t *testing.T) []*models.NodeOperator { - t.Helper() - var out []*models.NodeOperator - err := json.Unmarshal([]byte(testNopsWithChainConfigs), &out) - require.NoError(t, err) - require.Len(t, out, 2, "wrong number of nops") - return out -} diff --git a/deployment/environment/clo/testdata/keystone_nops.json b/deployment/environment/clo/testdata/keystone_nops.json deleted file mode 100644 index 679a85935a4..00000000000 --- a/deployment/environment/clo/testdata/keystone_nops.json +++ /dev/null @@ -1,3162 +0,0 @@ -[ - { - "id": "67", - "keys": [ - "keystone-09" - ], - "name": "Chainlink Keystone Node Operator 9", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "780", - "name": "Chainlink Sepolia Prod Keystone One 9", - "publicKey": "412dc6fe48ea4e34baaa77da2e3b032d39b938597b6f3d61fe7ed183a827a431", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xbA8E21dFaa0501fCD43146d0b5F21c2B8E0eEdfB", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE8TxNr5dM4U", - "publicKey": "147d5cc651819b093cd2fdff9760f0f0f77b7ef7798d9e24fc6a350b7300e5d9" - }, - "ocrKeyBundle": { - "bundleID": "1c28e76d180d1ed1524e61845fa58a384415de7e51017edf1f8c553e28357772", - "configPublicKey": "09fced0207611ed618bf0759ab128d9797e15b18e46436be1a56a91e4043ec0e", - "offchainPublicKey": "c805572b813a072067eab2087ddbee8aa719090e12890b15c01094f0d3f74a5f", - "onchainSigningAddress": "679296b7c1eb4948efcc87efc550940a182e610c" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x0b04cE574E80Da73191Ec141c0016a54A6404056", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE8TxNr5dM4U", - "publicKey": "147d5cc651819b093cd2fdff9760f0f0f77b7ef7798d9e24fc6a350b7300e5d9" - }, - "ocrKeyBundle": { - "bundleID": "1c28e76d180d1ed1524e61845fa58a384415de7e51017edf1f8c553e28357772", - "configPublicKey": "09fced0207611ed618bf0759ab128d9797e15b18e46436be1a56a91e4043ec0e", - "offchainPublicKey": "c805572b813a072067eab2087ddbee8aa719090e12890b15c01094f0d3f74a5f", - "onchainSigningAddress": "679296b7c1eb4948efcc87efc550940a182e610c" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - }, - { - "id": "818", - "name": "Chainlink Sepolia Prod Keystone Cap One 9", - "publicKey": "3f5bbcb4b0409e6ea39d824f1837787484475fffb12e5e4a70509756ef6c7f9a", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x9b74f08bD7269919C0597C0E00e70ef2A66829db", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWPG6X2RgqoSWtM3kvETV6kK4ki8FftaBkwvFWk8yKRBkz", - "publicKey": "c7bf55cf625a55470b0c56c3e51ad175c9dd0d42ca48246c205c715b7495937f" - }, - "ocrKeyBundle": { - "bundleID": "aa717effd7d28374c5980dbd9583dcff5e0800e7100051c6c8418899648dffbf", - "configPublicKey": "3fd95a3839f15adcdff573e6fbf07d06d78fbfeac5eb683f67e70226c1983c44", - "offchainPublicKey": "2b8b8d091c6f4446365f463e6132d699206bbddd38284e8e14ae0443382f297c", - "onchainSigningAddress": "b05b138a987fceffa68f79bdbb36a1faf8d3d964" - }, - "plugins": {} - } - }, - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0x662B6B119f7fc9Dc2A526395A9EA88AE79A1192F", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWPG6X2RgqoSWtM3kvETV6kK4ki8FftaBkwvFWk8yKRBkz", - "publicKey": "c7bf55cf625a55470b0c56c3e51ad175c9dd0d42ca48246c205c715b7495937f" - }, - "ocrKeyBundle": { - "bundleID": "aa717effd7d28374c5980dbd9583dcff5e0800e7100051c6c8418899648dffbf", - "configPublicKey": "3fd95a3839f15adcdff573e6fbf07d06d78fbfeac5eb683f67e70226c1983c44", - "offchainPublicKey": "2b8b8d091c6f4446365f463e6132d699206bbddd38284e8e14ae0443382f297c", - "onchainSigningAddress": "b05b138a987fceffa68f79bdbb36a1faf8d3d964" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0x34431021e0E07c75816226697Af6Ef02725e36af", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWPG6X2RgqoSWtM3kvETV6kK4ki8FftaBkwvFWk8yKRBkz", - "publicKey": "c7bf55cf625a55470b0c56c3e51ad175c9dd0d42ca48246c205c715b7495937f" - }, - "ocrKeyBundle": { - "bundleID": "aa717effd7d28374c5980dbd9583dcff5e0800e7100051c6c8418899648dffbf", - "configPublicKey": "3fd95a3839f15adcdff573e6fbf07d06d78fbfeac5eb683f67e70226c1983c44", - "offchainPublicKey": "2b8b8d091c6f4446365f463e6132d699206bbddd38284e8e14ae0443382f297c", - "onchainSigningAddress": "b05b138a987fceffa68f79bdbb36a1faf8d3d964" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xB5988d5d9ADd3d98CF45211bE37cf9b3372054C9", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWPG6X2RgqoSWtM3kvETV6kK4ki8FftaBkwvFWk8yKRBkz", - "publicKey": "c7bf55cf625a55470b0c56c3e51ad175c9dd0d42ca48246c205c715b7495937f" - }, - "ocrKeyBundle": { - "bundleID": "aa717effd7d28374c5980dbd9583dcff5e0800e7100051c6c8418899648dffbf", - "configPublicKey": "3fd95a3839f15adcdff573e6fbf07d06d78fbfeac5eb683f67e70226c1983c44", - "offchainPublicKey": "2b8b8d091c6f4446365f463e6132d699206bbddd38284e8e14ae0443382f297c", - "onchainSigningAddress": "b05b138a987fceffa68f79bdbb36a1faf8d3d964" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T19:00:07.113658Z" - }, - { - "id": "68", - "keys": [ - "keystone-08" - ], - "name": "Chainlink Keystone Node Operator 8", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "781", - "name": "Chainlink Sepolia Prod Keystone One 8", - "publicKey": "1141dd1e46797ced9b0fbad49115f18507f6f6e6e3cc86e7e5ba169e58645adc", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xEa4bC3638660D78Da56f39f6680dCDD0cEAaD2c6", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWAUagqMycsro27kFznSQRHbhfCBLx8nKD4ptTiUGDe38c", - "publicKey": "09ca39cd924653c72fbb0e458b629c3efebdad3e29e7cd0b5760754d919ed829" - }, - "ocrKeyBundle": { - "bundleID": "be0d639de3ae3cbeaa31ca369514f748ba1d271145cba6796bcc12aace2f64c3", - "configPublicKey": "e3d4d7a7372a3b1110db0290ab3649eb5fbb0daf6cf3ae02cfe5f367700d9264", - "offchainPublicKey": "ad08c2a5878cada53521f4e2bb449f191ccca7899246721a0deeea19f7b83f70", - "onchainSigningAddress": "8c2aa1e6fad88a6006dfb116eb866cbad2910314" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x31B179dcF8f9036C30f04bE578793e51bF14A39E", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWAUagqMycsro27kFznSQRHbhfCBLx8nKD4ptTiUGDe38c", - "publicKey": "09ca39cd924653c72fbb0e458b629c3efebdad3e29e7cd0b5760754d919ed829" - }, - "ocrKeyBundle": { - "bundleID": "be0d639de3ae3cbeaa31ca369514f748ba1d271145cba6796bcc12aace2f64c3", - "configPublicKey": "e3d4d7a7372a3b1110db0290ab3649eb5fbb0daf6cf3ae02cfe5f367700d9264", - "offchainPublicKey": "ad08c2a5878cada53521f4e2bb449f191ccca7899246721a0deeea19f7b83f70", - "onchainSigningAddress": "8c2aa1e6fad88a6006dfb116eb866cbad2910314" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - }, - { - "id": "817", - "name": "Chainlink Sepolia Prod Keystone Cap One 8", - "publicKey": "2346da196a82c88fe6c315d2e4d0dddacf4590a172b20adb6f27a8601ca0540d", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xa5C7133aBD35F9d742bD2997D693A507c5eBf4Ac", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWNfg9cYxEri1zGbdCZ87DekmruYY6J1wUobEwNNVewMpT", - "publicKey": "beee088bccea272eb6473fcc1cd3e22f2fc8d3a253a6398b69f5aab94070e690" - }, - "ocrKeyBundle": { - "bundleID": "9fba2d29874bb06b07272bd9141f096c1987d790bb0f81c3ffaf66d11cdac4f2", - "configPublicKey": "66dec87065de79e64ed4edd2478ec40a66f955af56e7b837729f464f8487d713", - "offchainPublicKey": "a0f59d50078c77812da8d3077f552209adfb58e76b635e008b6b0f872ce52139", - "onchainSigningAddress": "ed25406f1ef2e1381f6e1e04341f1a6e8b4eacea" - }, - "plugins": {} - } - }, - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0x9fd869f5baADb79F9b7C58c0855fcAc0384e1d4B", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWNfg9cYxEri1zGbdCZ87DekmruYY6J1wUobEwNNVewMpT", - "publicKey": "beee088bccea272eb6473fcc1cd3e22f2fc8d3a253a6398b69f5aab94070e690" - }, - "ocrKeyBundle": { - "bundleID": "9fba2d29874bb06b07272bd9141f096c1987d790bb0f81c3ffaf66d11cdac4f2", - "configPublicKey": "66dec87065de79e64ed4edd2478ec40a66f955af56e7b837729f464f8487d713", - "offchainPublicKey": "a0f59d50078c77812da8d3077f552209adfb58e76b635e008b6b0f872ce52139", - "onchainSigningAddress": "ed25406f1ef2e1381f6e1e04341f1a6e8b4eacea" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0xe477E4C2e335E9b839665d710dE77CFECa9C43A7", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWNfg9cYxEri1zGbdCZ87DekmruYY6J1wUobEwNNVewMpT", - "publicKey": "beee088bccea272eb6473fcc1cd3e22f2fc8d3a253a6398b69f5aab94070e690" - }, - "ocrKeyBundle": { - "bundleID": "9fba2d29874bb06b07272bd9141f096c1987d790bb0f81c3ffaf66d11cdac4f2", - "configPublicKey": "66dec87065de79e64ed4edd2478ec40a66f955af56e7b837729f464f8487d713", - "offchainPublicKey": "a0f59d50078c77812da8d3077f552209adfb58e76b635e008b6b0f872ce52139", - "onchainSigningAddress": "ed25406f1ef2e1381f6e1e04341f1a6e8b4eacea" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x056A1275DD670205aba10D8fC9bB597777a65030", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWNfg9cYxEri1zGbdCZ87DekmruYY6J1wUobEwNNVewMpT", - "publicKey": "beee088bccea272eb6473fcc1cd3e22f2fc8d3a253a6398b69f5aab94070e690" - }, - "ocrKeyBundle": { - "bundleID": "9fba2d29874bb06b07272bd9141f096c1987d790bb0f81c3ffaf66d11cdac4f2", - "configPublicKey": "66dec87065de79e64ed4edd2478ec40a66f955af56e7b837729f464f8487d713", - "offchainPublicKey": "a0f59d50078c77812da8d3077f552209adfb58e76b635e008b6b0f872ce52139", - "onchainSigningAddress": "ed25406f1ef2e1381f6e1e04341f1a6e8b4eacea" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:26:37.622463Z" - }, - { - "id": "69", - "keys": [ - "keystone-07" - ], - "name": "Chainlink Keystone Node Operator 7", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "782", - "name": "Chainlink Sepolia Prod Keystone One 7", - "publicKey": "b473091fe1d4dbbc26ad71c67b4432f8f4280e06bab5e2122a92f4ab8b6ff2f5", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x65bE4739E187a39b859766C143b569acd5BE234d", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQMCj73V5xmCd6C5VsJr7rbFG2TF9LwVcLiiBqXps9MgC", - "publicKey": "d7e9f2252b09edf0802a65b60bc9956691747894cb3ab9fefd072adf742eb9f1" - }, - "ocrKeyBundle": { - "bundleID": "e6d6ffec6cff01ac20d57bc42626c8e955293f232d383bf468351d867a7b8213", - "configPublicKey": "4d2f75f98b911c20fe7808384312d8b913e6b7a98c34d05c6e461434c92b4502", - "offchainPublicKey": "01496edce35663071d74472e02119432ba059b3904d205e4358014410e4f2be3", - "onchainSigningAddress": "213803bb9f9715379aaf11aadb0212369701dc0a" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x9ad9f3AD49e5aB0F28bD694d211a90297bD90D7f", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQMCj73V5xmCd6C5VsJr7rbFG2TF9LwVcLiiBqXps9MgC", - "publicKey": "d7e9f2252b09edf0802a65b60bc9956691747894cb3ab9fefd072adf742eb9f1" - }, - "ocrKeyBundle": { - "bundleID": "e6d6ffec6cff01ac20d57bc42626c8e955293f232d383bf468351d867a7b8213", - "configPublicKey": "4d2f75f98b911c20fe7808384312d8b913e6b7a98c34d05c6e461434c92b4502", - "offchainPublicKey": "01496edce35663071d74472e02119432ba059b3904d205e4358014410e4f2be3", - "onchainSigningAddress": "213803bb9f9715379aaf11aadb0212369701dc0a" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - }, - { - "id": "816", - "name": "Chainlink Sepolia Prod Keystone Cap One 7", - "publicKey": "50d4e3393516d1998e5c39874d7c0da2291e4e3727f8baac4380e9f5573cc648", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x0ba7c1096B701A862bBCe7F13E9D33eED7e33c1D", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQswQr8fxJG5ieMrayptGV4rvCjDWPCFtfkqm4L6NZbbb", - "publicKey": "dfc9a26dc022bd244c13d62ca88bbe62ca996065bd23224e1f1b77128914d84e" - }, - "ocrKeyBundle": { - "bundleID": "d4566a0c2f256e59733ad2a6dff9f388a1e00b2e65ec1cff7590cb59028888cd", - "configPublicKey": "58db0da621471e616615b8c1c1658ee3b7afbfa64662ce28b38272a95964052c", - "offchainPublicKey": "262fee9de8dd0c8758ba78de8873fdb6705c45ce331bc16ac81dc5b5f0b9680f", - "onchainSigningAddress": "516a9990d3a202b25c2cdd2f6316f4d066543e5d" - }, - "plugins": {} - } - }, - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0xcC44eD47023Bd88B82092A708c38609e8Fc2D197", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQswQr8fxJG5ieMrayptGV4rvCjDWPCFtfkqm4L6NZbbb", - "publicKey": "dfc9a26dc022bd244c13d62ca88bbe62ca996065bd23224e1f1b77128914d84e" - }, - "ocrKeyBundle": { - "bundleID": "d4566a0c2f256e59733ad2a6dff9f388a1e00b2e65ec1cff7590cb59028888cd", - "configPublicKey": "58db0da621471e616615b8c1c1658ee3b7afbfa64662ce28b38272a95964052c", - "offchainPublicKey": "262fee9de8dd0c8758ba78de8873fdb6705c45ce331bc16ac81dc5b5f0b9680f", - "onchainSigningAddress": "516a9990d3a202b25c2cdd2f6316f4d066543e5d" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0x0E8F4E699cd331022FaA2Ad75E500e70303C8767", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQswQr8fxJG5ieMrayptGV4rvCjDWPCFtfkqm4L6NZbbb", - "publicKey": "dfc9a26dc022bd244c13d62ca88bbe62ca996065bd23224e1f1b77128914d84e" - }, - "ocrKeyBundle": { - "bundleID": "d4566a0c2f256e59733ad2a6dff9f388a1e00b2e65ec1cff7590cb59028888cd", - "configPublicKey": "58db0da621471e616615b8c1c1658ee3b7afbfa64662ce28b38272a95964052c", - "offchainPublicKey": "262fee9de8dd0c8758ba78de8873fdb6705c45ce331bc16ac81dc5b5f0b9680f", - "onchainSigningAddress": "516a9990d3a202b25c2cdd2f6316f4d066543e5d" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x49c36b3BEc6b6e0e77305273FAFC68f479630535", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQswQr8fxJG5ieMrayptGV4rvCjDWPCFtfkqm4L6NZbbb", - "publicKey": "dfc9a26dc022bd244c13d62ca88bbe62ca996065bd23224e1f1b77128914d84e" - }, - "ocrKeyBundle": { - "bundleID": "d4566a0c2f256e59733ad2a6dff9f388a1e00b2e65ec1cff7590cb59028888cd", - "configPublicKey": "58db0da621471e616615b8c1c1658ee3b7afbfa64662ce28b38272a95964052c", - "offchainPublicKey": "262fee9de8dd0c8758ba78de8873fdb6705c45ce331bc16ac81dc5b5f0b9680f", - "onchainSigningAddress": "516a9990d3a202b25c2cdd2f6316f4d066543e5d" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:30:51.07624Z" - }, - { - "id": "70", - "keys": [ - "keystone-06" - ], - "name": "Chainlink Keystone Node Operator 6", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "783", - "name": "Chainlink Sepolia Prod Keystone One 6", - "publicKey": "75ac63fc97a31e31168084e0de8ccd2bea90059b609d962f3e43fc296cdba28d", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x8706E716fc1ee972F3E4D42D42711Aa175Aa654A", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWNJ8de3PUURZ2oucrVTpnRTqNBTUYwHLQjK9LzN3E6Mfn", - "publicKey": "b96933429b1a81c811e1195389d7733e936b03e8086e75ea1fa92c61564b6c31" - }, - "ocrKeyBundle": { - "bundleID": "62d36269d916b4834b17dc6d637c1c39b0895396249a0845764c898e83f63525", - "configPublicKey": "8c6c7d889ac6cc9e663ae48073bbf130fae105d6a3689636db27752e3e3e6816", - "offchainPublicKey": "aa3419628ea3536783742d17d8adf05681aa6a6bd2b206fbde78c7e5aa38586d", - "onchainSigningAddress": "4885973b2fcf061d5cdfb8f74c5139bd3056e9da" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x19e10B063a62B1574AE19020A64fDe6419892dA6", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWNJ8de3PUURZ2oucrVTpnRTqNBTUYwHLQjK9LzN3E6Mfn", - "publicKey": "b96933429b1a81c811e1195389d7733e936b03e8086e75ea1fa92c61564b6c31" - }, - "ocrKeyBundle": { - "bundleID": "62d36269d916b4834b17dc6d637c1c39b0895396249a0845764c898e83f63525", - "configPublicKey": "8c6c7d889ac6cc9e663ae48073bbf130fae105d6a3689636db27752e3e3e6816", - "offchainPublicKey": "aa3419628ea3536783742d17d8adf05681aa6a6bd2b206fbde78c7e5aa38586d", - "onchainSigningAddress": "4885973b2fcf061d5cdfb8f74c5139bd3056e9da" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - }, - { - "id": "815", - "name": "Chainlink Sepolia Prod Keystone Cap One 6", - "publicKey": "2669981add3071fae5dfd760fe97e7d2b90157f86b40227f306f1f3906099fc3", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x405eE4ad3E79786f899810ff6de16a83A920Db5D", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWHB1ucYgRqrocS6t834wL5XaB11JSPgKwzB6QwRPzRayu", - "publicKey": "6d4c18afa813bf7eec73e98a260294bce4b0b26eb9f6efceb2c9402eead56c98" - }, - "ocrKeyBundle": { - "bundleID": "d55283594d4e2c3e507f81ea9ad96261ebec1b1e8579bb1392ca22f7dc9b471b", - "configPublicKey": "32d5b6d38147fa23ec1dc4eeb240e2e70ea768b9a5182676075acd5a2ab2794c", - "offchainPublicKey": "9922cb5c0ae08f0b917979593824bde7ddad0935950e2835914acc34f6cd62f3", - "onchainSigningAddress": "bca900017893ea1366c110941d698d078c2b93ca" - }, - "plugins": {} - } - }, - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0x58D39d629ae9f904b0Ae509179b9e7c9B0184cee", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWHB1ucYgRqrocS6t834wL5XaB11JSPgKwzB6QwRPzRayu", - "publicKey": "6d4c18afa813bf7eec73e98a260294bce4b0b26eb9f6efceb2c9402eead56c98" - }, - "ocrKeyBundle": { - "bundleID": "d55283594d4e2c3e507f81ea9ad96261ebec1b1e8579bb1392ca22f7dc9b471b", - "configPublicKey": "32d5b6d38147fa23ec1dc4eeb240e2e70ea768b9a5182676075acd5a2ab2794c", - "offchainPublicKey": "9922cb5c0ae08f0b917979593824bde7ddad0935950e2835914acc34f6cd62f3", - "onchainSigningAddress": "bca900017893ea1366c110941d698d078c2b93ca" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0x34bFe10F4f4e1101b019639ABd5E5eE5186B80E6", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWHB1ucYgRqrocS6t834wL5XaB11JSPgKwzB6QwRPzRayu", - "publicKey": "6d4c18afa813bf7eec73e98a260294bce4b0b26eb9f6efceb2c9402eead56c98" - }, - "ocrKeyBundle": { - "bundleID": "d55283594d4e2c3e507f81ea9ad96261ebec1b1e8579bb1392ca22f7dc9b471b", - "configPublicKey": "32d5b6d38147fa23ec1dc4eeb240e2e70ea768b9a5182676075acd5a2ab2794c", - "offchainPublicKey": "9922cb5c0ae08f0b917979593824bde7ddad0935950e2835914acc34f6cd62f3", - "onchainSigningAddress": "bca900017893ea1366c110941d698d078c2b93ca" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x1741EB7468A490b4A9BA6f4CC7A47B82EcD65c4c", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWHB1ucYgRqrocS6t834wL5XaB11JSPgKwzB6QwRPzRayu", - "publicKey": "6d4c18afa813bf7eec73e98a260294bce4b0b26eb9f6efceb2c9402eead56c98" - }, - "ocrKeyBundle": { - "bundleID": "d55283594d4e2c3e507f81ea9ad96261ebec1b1e8579bb1392ca22f7dc9b471b", - "configPublicKey": "32d5b6d38147fa23ec1dc4eeb240e2e70ea768b9a5182676075acd5a2ab2794c", - "offchainPublicKey": "9922cb5c0ae08f0b917979593824bde7ddad0935950e2835914acc34f6cd62f3", - "onchainSigningAddress": "bca900017893ea1366c110941d698d078c2b93ca" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:32:14.024795Z" - }, - { - "id": "71", - "keys": [ - "keystone-05" - ], - "name": "Chainlink Keystone Node Operator 5", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "784", - "name": "Chainlink Sepolia Prod Keystone One 5", - "publicKey": "4542f4fd2ed150c8c976b39802fe3d994aec3ac94fd11e7817f693b1c9a1dabb", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xcea9f5C042130dD35Eff5B5a6E2361A0276570e3", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWR8d5kbZb7YiQWKpT1J1PfMqNaGAmb4jBFx9DWag4hpSZ", - "publicKey": "e38c9f2760db006f070e9cc1bc1c2269ad033751adaa85d022fb760cbc5b5ef6" - }, - "ocrKeyBundle": { - "bundleID": "99fad0362cc8dc8a57a8e616e68133a6d5a8834e08a1b4819710f0e912df5abc", - "configPublicKey": "36de4924cf11938b4461aea1ce99cb640e9603d9a7c294ab6c54acd51d575a49", - "offchainPublicKey": "283471ed66d61fbe11f64eff65d738b59a0301c9a4f846280db26c64c9fdd3f8", - "onchainSigningAddress": "657587eb55cecd6f90b97297b611c3024e488cc0" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xdAd1F3F8ec690cf335D46c50EdA5547CeF875161", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWR8d5kbZb7YiQWKpT1J1PfMqNaGAmb4jBFx9DWag4hpSZ", - "publicKey": "e38c9f2760db006f070e9cc1bc1c2269ad033751adaa85d022fb760cbc5b5ef6" - }, - "ocrKeyBundle": { - "bundleID": "99fad0362cc8dc8a57a8e616e68133a6d5a8834e08a1b4819710f0e912df5abc", - "configPublicKey": "36de4924cf11938b4461aea1ce99cb640e9603d9a7c294ab6c54acd51d575a49", - "offchainPublicKey": "283471ed66d61fbe11f64eff65d738b59a0301c9a4f846280db26c64c9fdd3f8", - "onchainSigningAddress": "657587eb55cecd6f90b97297b611c3024e488cc0" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - }, - { - "id": "814", - "name": "Chainlink Sepolia Prod Keystone Cap One 5", - "publicKey": "94e9ee398547f1564b8b5f72c6148e511919ed0e59b94ae848d63685108f2ab4", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xbd1ee3165178D3A3E38458a9Fb1d6BF7fb5C443e", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCiwWc97Q3Z9YUGZcAf46TMLg1uMvrEDa4gT6HZUFFCB1", - "publicKey": "2b2f46bf3b7ab2f39a7fec18166a6ebbc0a72209e920c33933f9adf07b101cc0" - }, - "ocrKeyBundle": { - "bundleID": "bf1736a09452daa0923f2c680f3fa6362ae652294e80ce72d923b304b0dcbb13", - "configPublicKey": "4ebd2a563c458485d2698d06142daa37ea2bee706b4a1a71c8435f2ec254506a", - "offchainPublicKey": "8577b96b270b36e74eb5d411caa14353cdadea599d6d6aa9cccf534ce31f1ef5", - "onchainSigningAddress": "b6727a31772b71d15e3120bfd618545292e1f9df" - }, - "plugins": {} - } - }, - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0x9b6284B5775E46fB02C1a589596EF07c35b55377", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCiwWc97Q3Z9YUGZcAf46TMLg1uMvrEDa4gT6HZUFFCB1", - "publicKey": "2b2f46bf3b7ab2f39a7fec18166a6ebbc0a72209e920c33933f9adf07b101cc0" - }, - "ocrKeyBundle": { - "bundleID": "bf1736a09452daa0923f2c680f3fa6362ae652294e80ce72d923b304b0dcbb13", - "configPublicKey": "4ebd2a563c458485d2698d06142daa37ea2bee706b4a1a71c8435f2ec254506a", - "offchainPublicKey": "8577b96b270b36e74eb5d411caa14353cdadea599d6d6aa9cccf534ce31f1ef5", - "onchainSigningAddress": "b6727a31772b71d15e3120bfd618545292e1f9df" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0xD83DCED517E4df64e913B97b3d0A906e4CA63d43", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCiwWc97Q3Z9YUGZcAf46TMLg1uMvrEDa4gT6HZUFFCB1", - "publicKey": "2b2f46bf3b7ab2f39a7fec18166a6ebbc0a72209e920c33933f9adf07b101cc0" - }, - "ocrKeyBundle": { - "bundleID": "bf1736a09452daa0923f2c680f3fa6362ae652294e80ce72d923b304b0dcbb13", - "configPublicKey": "4ebd2a563c458485d2698d06142daa37ea2bee706b4a1a71c8435f2ec254506a", - "offchainPublicKey": "8577b96b270b36e74eb5d411caa14353cdadea599d6d6aa9cccf534ce31f1ef5", - "onchainSigningAddress": "b6727a31772b71d15e3120bfd618545292e1f9df" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xFF1218066b4b5Cd9dE2A73639862082bcC98bf0D", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCiwWc97Q3Z9YUGZcAf46TMLg1uMvrEDa4gT6HZUFFCB1", - "publicKey": "2b2f46bf3b7ab2f39a7fec18166a6ebbc0a72209e920c33933f9adf07b101cc0" - }, - "ocrKeyBundle": { - "bundleID": "bf1736a09452daa0923f2c680f3fa6362ae652294e80ce72d923b304b0dcbb13", - "configPublicKey": "4ebd2a563c458485d2698d06142daa37ea2bee706b4a1a71c8435f2ec254506a", - "offchainPublicKey": "8577b96b270b36e74eb5d411caa14353cdadea599d6d6aa9cccf534ce31f1ef5", - "onchainSigningAddress": "b6727a31772b71d15e3120bfd618545292e1f9df" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:38:35.588611Z" - }, - { - "id": "72", - "keys": [ - "keystone-04" - ], - "name": "Chainlink Keystone Node Operator 4", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "785", - "name": "Chainlink Sepolia Prod Keystone One 4", - "publicKey": "07e0ffc57b6263604df517b94bd986169451a3c90600a855bb19212dc575de54", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x0be7Df958604166D9Bf0F727F0AC7A4Fb0f5B8a1", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWHqR1w26yHatTSZQW3xbRct9SxWzVj9X4SpU916Hy8jYg", - "publicKey": "77224be9d052343b1d17156a1e463625c0d746468d4f5a44cddd452365b1d4ed" - }, - "ocrKeyBundle": { - "bundleID": "8e563a16ec5a802345b162d0f31149e8d5055014a31847d7b20d6de500aa48bd", - "configPublicKey": "c812eab2415f45cc1d2afdb2be2e3ea419bb7851acfc30c07b4df42c856e8f74", - "offchainPublicKey": "2a4c7dec127fdd8145e48c5edb9467225098bd8c8ad1dade868325b787affbde", - "onchainSigningAddress": "a6f35436cb7bffd615cc47a0a04aa0a78696a144" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x6F5cAb24Fb7412bB516b3468b9F3a9c471d25fE5", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWHqR1w26yHatTSZQW3xbRct9SxWzVj9X4SpU916Hy8jYg", - "publicKey": "77224be9d052343b1d17156a1e463625c0d746468d4f5a44cddd452365b1d4ed" - }, - "ocrKeyBundle": { - "bundleID": "8e563a16ec5a802345b162d0f31149e8d5055014a31847d7b20d6de500aa48bd", - "configPublicKey": "c812eab2415f45cc1d2afdb2be2e3ea419bb7851acfc30c07b4df42c856e8f74", - "offchainPublicKey": "2a4c7dec127fdd8145e48c5edb9467225098bd8c8ad1dade868325b787affbde", - "onchainSigningAddress": "a6f35436cb7bffd615cc47a0a04aa0a78696a144" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - }, - { - "id": "813", - "name": "Chainlink Sepolia Prod Keystone Cap One 4", - "publicKey": "a618fe2d3260151957d105d2dd593dddaad20c45dc6ae8eab265504e6585a02c", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xE73E4D047DA32De40C7008075aEb9F60C8AF3C90", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWPMfQRpMy3wYzSMe3BLS8GFuC3fauk7FhTtgfbtp6T6jT", - "publicKey": "c92c6c81f3dff17c05577b9f87177d735d797a3ceedc0fa1395682dfbb66a8d2" - }, - "ocrKeyBundle": { - "bundleID": "fbcfd8420c2ebc450c81fcf72c6673fdd786702c881467e69817c20350bf819b", - "configPublicKey": "282a47a24fd976134f25a99f6370e072f228098010d2594d849d0a4c2788f878", - "offchainPublicKey": "1a7902a01e27818cda034637fdce603a265bc380934324b6f48cf23873234ec6", - "onchainSigningAddress": "7e799378dda3dcdc503233735f09150f0684be19" - }, - "plugins": {} - } - }, - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0x7501ff3462fd2133f2E1F93DB7Ec514988B43E56", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWPMfQRpMy3wYzSMe3BLS8GFuC3fauk7FhTtgfbtp6T6jT", - "publicKey": "c92c6c81f3dff17c05577b9f87177d735d797a3ceedc0fa1395682dfbb66a8d2" - }, - "ocrKeyBundle": { - "bundleID": "fbcfd8420c2ebc450c81fcf72c6673fdd786702c881467e69817c20350bf819b", - "configPublicKey": "282a47a24fd976134f25a99f6370e072f228098010d2594d849d0a4c2788f878", - "offchainPublicKey": "1a7902a01e27818cda034637fdce603a265bc380934324b6f48cf23873234ec6", - "onchainSigningAddress": "7e799378dda3dcdc503233735f09150f0684be19" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0xef080765890a3F697C4920609621fe301Dd34A70", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWPMfQRpMy3wYzSMe3BLS8GFuC3fauk7FhTtgfbtp6T6jT", - "publicKey": "c92c6c81f3dff17c05577b9f87177d735d797a3ceedc0fa1395682dfbb66a8d2" - }, - "ocrKeyBundle": { - "bundleID": "fbcfd8420c2ebc450c81fcf72c6673fdd786702c881467e69817c20350bf819b", - "configPublicKey": "282a47a24fd976134f25a99f6370e072f228098010d2594d849d0a4c2788f878", - "offchainPublicKey": "1a7902a01e27818cda034637fdce603a265bc380934324b6f48cf23873234ec6", - "onchainSigningAddress": "7e799378dda3dcdc503233735f09150f0684be19" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x860235D5Db42eF568665900BBD6bA3DB2fA4f33f", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWPMfQRpMy3wYzSMe3BLS8GFuC3fauk7FhTtgfbtp6T6jT", - "publicKey": "c92c6c81f3dff17c05577b9f87177d735d797a3ceedc0fa1395682dfbb66a8d2" - }, - "ocrKeyBundle": { - "bundleID": "fbcfd8420c2ebc450c81fcf72c6673fdd786702c881467e69817c20350bf819b", - "configPublicKey": "282a47a24fd976134f25a99f6370e072f228098010d2594d849d0a4c2788f878", - "offchainPublicKey": "1a7902a01e27818cda034637fdce603a265bc380934324b6f48cf23873234ec6", - "onchainSigningAddress": "7e799378dda3dcdc503233735f09150f0684be19" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:39:26.24249Z" - }, - { - "id": "73", - "keys": [ - "keystone-03", - "keystone-bt-03" - ], - "name": "Chainlink Keystone Node Operator 3", - "metadata": { - "nodeCount": 3, - "jobCount": 5 - }, - "nodes": [ - { - "id": "786", - "name": "\tChainlink Sepolia Prod Keystone One 3", - "publicKey": "487901e0c0a9d3c66e7cfc50f3a9e3cdbfdf1b0107273d73d94a91d278545516", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x3Be73A57a36E5ab00DcceD755B4bfF8bb99e52b2", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCcVLytqinD8xMn27NvomcQhj2mqMVzyGemz6oPwv1SMT", - "publicKey": "298834a041a056df58c839cb53d99b78558693042e54dff238f504f16d18d4b6" - }, - "ocrKeyBundle": { - "bundleID": "8843b5db0608f92dac38ca56775766a08db9ee82224a19595d04bd6c58b38fbd", - "configPublicKey": "63375a3d175364bd299e7cecf352cb3e469dd30116cf1418f2b7571fb46c4a4b", - "offchainPublicKey": "b4c4993d6c15fee63800db901a8b35fa419057610962caab1c1d7bed55709127", - "onchainSigningAddress": "6607c140e558631407f33bafbabd103863cee876" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xA9eFB53c513E413762b2Be5299D161d8E6e7278e", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCcVLytqinD8xMn27NvomcQhj2mqMVzyGemz6oPwv1SMT", - "publicKey": "298834a041a056df58c839cb53d99b78558693042e54dff238f504f16d18d4b6" - }, - "ocrKeyBundle": { - "bundleID": "8843b5db0608f92dac38ca56775766a08db9ee82224a19595d04bd6c58b38fbd", - "configPublicKey": "63375a3d175364bd299e7cecf352cb3e469dd30116cf1418f2b7571fb46c4a4b", - "offchainPublicKey": "b4c4993d6c15fee63800db901a8b35fa419057610962caab1c1d7bed55709127", - "onchainSigningAddress": "6607c140e558631407f33bafbabd103863cee876" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - }, - { - "id": "812", - "name": "Chainlink Sepolia Prod Keystone Cap One 3", - "publicKey": "f4cf97438c3ad86003e5c0368ab52c70f7fbb7f39ae0d7bf6dacbe16807e8a36", - "chainConfigs": [ - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0x646665317aF70313B3E83Ea1369A91de389DaCAe", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWAvLkcnc8Zttykk6gGeTWFiT6TqgovRHnb6Ym6QqjnLVM", - "publicKey": "1063921b717c3e32210d2803fe684cd818ea2a4a96e405373e5786c8a13c7600" - }, - "ocrKeyBundle": { - "bundleID": "5b46ab201ba66bd93bae6f41afc59c2e578e0f5682fbdf76e1b647fde6d6e8dd", - "configPublicKey": "a01d7d13f3e67ff84ff208cc44c923fe245d02d6029c91dc38422ef44f2bb26e", - "offchainPublicKey": "64eded06a47efc5e311799c1e1fa833cf78d17f079b2f6019c3247debe490439", - "onchainSigningAddress": "afca74e3b850a9435b2dc479ca8bc8e1b45dd0b2" - }, - "plugins": {} - } - }, - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0x3Ab2A4e4765A0374F727a9a9eCE893734e2928ec", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWAvLkcnc8Zttykk6gGeTWFiT6TqgovRHnb6Ym6QqjnLVM", - "publicKey": "1063921b717c3e32210d2803fe684cd818ea2a4a96e405373e5786c8a13c7600" - }, - "ocrKeyBundle": { - "bundleID": "5b46ab201ba66bd93bae6f41afc59c2e578e0f5682fbdf76e1b647fde6d6e8dd", - "configPublicKey": "a01d7d13f3e67ff84ff208cc44c923fe245d02d6029c91dc38422ef44f2bb26e", - "offchainPublicKey": "64eded06a47efc5e311799c1e1fa833cf78d17f079b2f6019c3247debe490439", - "onchainSigningAddress": "afca74e3b850a9435b2dc479ca8bc8e1b45dd0b2" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x9905E8C3A4f82037170a8c411CD8b11D4894066f", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWAvLkcnc8Zttykk6gGeTWFiT6TqgovRHnb6Ym6QqjnLVM", - "publicKey": "1063921b717c3e32210d2803fe684cd818ea2a4a96e405373e5786c8a13c7600" - }, - "ocrKeyBundle": { - "bundleID": "5b46ab201ba66bd93bae6f41afc59c2e578e0f5682fbdf76e1b647fde6d6e8dd", - "configPublicKey": "a01d7d13f3e67ff84ff208cc44c923fe245d02d6029c91dc38422ef44f2bb26e", - "offchainPublicKey": "64eded06a47efc5e311799c1e1fa833cf78d17f079b2f6019c3247debe490439", - "onchainSigningAddress": "afca74e3b850a9435b2dc479ca8bc8e1b45dd0b2" - }, - "plugins": {} - } - }, - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x762354eC86ea2253F5da27FF8b952Cb7Dec52B6D", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWAvLkcnc8Zttykk6gGeTWFiT6TqgovRHnb6Ym6QqjnLVM", - "publicKey": "1063921b717c3e32210d2803fe684cd818ea2a4a96e405373e5786c8a13c7600" - }, - "ocrKeyBundle": { - "bundleID": "5b46ab201ba66bd93bae6f41afc59c2e578e0f5682fbdf76e1b647fde6d6e8dd", - "configPublicKey": "a01d7d13f3e67ff84ff208cc44c923fe245d02d6029c91dc38422ef44f2bb26e", - "offchainPublicKey": "64eded06a47efc5e311799c1e1fa833cf78d17f079b2f6019c3247debe490439", - "onchainSigningAddress": "afca74e3b850a9435b2dc479ca8bc8e1b45dd0b2" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:40:30.499914Z" - }, - { - "id": "74", - "keys": [ - "keystone-02", - "keystone-bt-02" - ], - "name": "Chainlink Keystone Node Operator 2", - "metadata": { - "nodeCount": 3, - "jobCount": 5 - }, - "nodes": [ - { - "id": "787", - "name": "Chainlink Sepolia Prod Keystone One 2", - "publicKey": "7a166fbc816eb4a4dcb620d11c3ccac5c085d56b1972374100116f87619debb8", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x693bf95A3ef46E5dABe17d1A89dB1E83948aeD88", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWGDmBKZ7B3PynGrvfHTJMEecpjfHts9YK5NWk8oJuxcAo", - "publicKey": "5f247f61a6d5bfdd1d5064db0bd25fe443648133c6131975edb23481424e3d9c" - }, - "ocrKeyBundle": { - "bundleID": "1d20490fe469dd6af3d418cc310a6e835181fa13e8dc80156bcbe302b7afcd34", - "configPublicKey": "ee466234b3b2f65b13c848b17aa6a8d4e0aa0311d3bf8e77a64f20b04ed48d39", - "offchainPublicKey": "dba3c61e5f8bec594be481bcaf67ecea0d1c2950edb15b158ce3dbc77877def3", - "onchainSigningAddress": "d4dcc573e9d24a8b27a07bba670ba3a2ab36e5bb" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xCea84bC1881F3cE14BA13Dc3a00DC1Ff3D553fF0", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWGDmBKZ7B3PynGrvfHTJMEecpjfHts9YK5NWk8oJuxcAo", - "publicKey": "5f247f61a6d5bfdd1d5064db0bd25fe443648133c6131975edb23481424e3d9c" - }, - "ocrKeyBundle": { - "bundleID": "1d20490fe469dd6af3d418cc310a6e835181fa13e8dc80156bcbe302b7afcd34", - "configPublicKey": "ee466234b3b2f65b13c848b17aa6a8d4e0aa0311d3bf8e77a64f20b04ed48d39", - "offchainPublicKey": "dba3c61e5f8bec594be481bcaf67ecea0d1c2950edb15b158ce3dbc77877def3", - "onchainSigningAddress": "d4dcc573e9d24a8b27a07bba670ba3a2ab36e5bb" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - }, - { - "id": "811", - "name": "Chainlink Sepolia Prod Keystone Cap One 2", - "publicKey": "a1f112923513f13ede1ca8f982ea0ab6221d584b40cd57f0c82307ab79c0e69f", - "chainConfigs": [ - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0xbF1Ad47D99A65e230235537b47C8D1Dddb22FD53", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQhLYuAxx4WDKafnuhZUTix8Y24gtB92vEUpAC4EdH4VA", - "publicKey": "dd1268a3e7ed4b9c83b1227e5bf2558e6b77af585c66e88a06f1164a1a94f8ed" - }, - "ocrKeyBundle": { - "bundleID": "a11d9438035564bfe84fcfb513b579edbe173fa26c00331e71a010d00b856037", - "configPublicKey": "407cab2a04fa868f645c6848a53abdb8136b08441c50b191651c4f1a348ee700", - "offchainPublicKey": "64a3215839e5630f12ae66b4363f40d82e9c981118c304ca0c4ca5fc2c6e1f37", - "onchainSigningAddress": "6579d77791ee8f8116495dbe6fa6586980177230" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0xa8d4698f74a0A427c1b8ec4575d9dFdD17Be288c", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQhLYuAxx4WDKafnuhZUTix8Y24gtB92vEUpAC4EdH4VA", - "publicKey": "dd1268a3e7ed4b9c83b1227e5bf2558e6b77af585c66e88a06f1164a1a94f8ed" - }, - "ocrKeyBundle": { - "bundleID": "a11d9438035564bfe84fcfb513b579edbe173fa26c00331e71a010d00b856037", - "configPublicKey": "407cab2a04fa868f645c6848a53abdb8136b08441c50b191651c4f1a348ee700", - "offchainPublicKey": "64a3215839e5630f12ae66b4363f40d82e9c981118c304ca0c4ca5fc2c6e1f37", - "onchainSigningAddress": "6579d77791ee8f8116495dbe6fa6586980177230" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xf286c79b4a613a1fE480C8e4fB17B837E7D8ba03", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQhLYuAxx4WDKafnuhZUTix8Y24gtB92vEUpAC4EdH4VA", - "publicKey": "dd1268a3e7ed4b9c83b1227e5bf2558e6b77af585c66e88a06f1164a1a94f8ed" - }, - "ocrKeyBundle": { - "bundleID": "a11d9438035564bfe84fcfb513b579edbe173fa26c00331e71a010d00b856037", - "configPublicKey": "407cab2a04fa868f645c6848a53abdb8136b08441c50b191651c4f1a348ee700", - "offchainPublicKey": "64a3215839e5630f12ae66b4363f40d82e9c981118c304ca0c4ca5fc2c6e1f37", - "onchainSigningAddress": "6579d77791ee8f8116495dbe6fa6586980177230" - }, - "plugins": {} - } - }, - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xfe85A25cE2CB58b280CC0316305fC678Bf570f5e", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQhLYuAxx4WDKafnuhZUTix8Y24gtB92vEUpAC4EdH4VA", - "publicKey": "dd1268a3e7ed4b9c83b1227e5bf2558e6b77af585c66e88a06f1164a1a94f8ed" - }, - "ocrKeyBundle": { - "bundleID": "a11d9438035564bfe84fcfb513b579edbe173fa26c00331e71a010d00b856037", - "configPublicKey": "407cab2a04fa868f645c6848a53abdb8136b08441c50b191651c4f1a348ee700", - "offchainPublicKey": "64a3215839e5630f12ae66b4363f40d82e9c981118c304ca0c4ca5fc2c6e1f37", - "onchainSigningAddress": "6579d77791ee8f8116495dbe6fa6586980177230" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:41:33.205484Z" - }, - { - "id": "75", - "keys": [ - "keystone-01", - "keystone-bt-01" - ], - "name": "Chainlink Keystone Node Operator 1", - "metadata": { - "nodeCount": 3, - "jobCount": 5 - }, - "nodes": [ - { - "id": "788", - "name": "Chainlink Sepolia Prod Keystone One 1", - "publicKey": "28b91143ec9111796a7d63e14c1cf6bb01b4ed59667ab54f5bc72ebe49c881be", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xe45a754B30FdE9852A826F58c6bd94Fa6554CE96", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCbDiL7sP9BVby5KaZqPpaVP1RBokoa9ShzH5WhkYX46v", - "publicKey": "2934f31f278e5c60618f85861bd6add54a4525d79a642019bdc87d75d26372c3" - }, - "ocrKeyBundle": { - "bundleID": "7a9b75510b8d09932b98142419bef52436ff725dd9395469473b487ef87fdfb0", - "configPublicKey": "2c45fec2320f6bcd36444529a86d9f8b4439499a5d8272dec9bcbbebb5e1bf01", - "offchainPublicKey": "255096a3b7ade10e29c648e0b407fc486180464f713446b1da04f013df6179c8", - "onchainSigningAddress": "8258f4c4761cc445333017608044a204fd0c006a" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x415aa1E9a1bcB3929ed92bFa1F9735Dc0D45AD31", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCbDiL7sP9BVby5KaZqPpaVP1RBokoa9ShzH5WhkYX46v", - "publicKey": "2934f31f278e5c60618f85861bd6add54a4525d79a642019bdc87d75d26372c3" - }, - "ocrKeyBundle": { - "bundleID": "7a9b75510b8d09932b98142419bef52436ff725dd9395469473b487ef87fdfb0", - "configPublicKey": "2c45fec2320f6bcd36444529a86d9f8b4439499a5d8272dec9bcbbebb5e1bf01", - "offchainPublicKey": "255096a3b7ade10e29c648e0b407fc486180464f713446b1da04f013df6179c8", - "onchainSigningAddress": "8258f4c4761cc445333017608044a204fd0c006a" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - }, - { - "id": "810", - "name": "Chainlink Sepolia Prod Keystone Cap One 1", - "publicKey": "9ef27cd1855a0ed6932be33c80d7cd9c178307e5a240dbeb9055946359dc5d7f", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xBB465BCa1b289269F2a95a36f5B6fD006Af56ede", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMNg1a7HvNWuHAPMdveWr1J6NNCVBU1Z4w5swzepT5Wvf", - "publicKey": "abb750e04bee21d830c6ce0f08180853466139fc6055c6737614797c0704d59c" - }, - "ocrKeyBundle": { - "bundleID": "0d176a4c2d68c619d237e419c31a030e5b2162ee031baa8ebc8472623da9b067", - "configPublicKey": "43e4dbf80a9c818a7d35c080f61b6f8f9b175fa1217b1d01168140da75322d5c", - "offchainPublicKey": "707db88237aaaaddc22bf0fe914540ea7b8bbfbe5cf88349cabb26e34762237c", - "onchainSigningAddress": "ac08f52ec257ddbb493e7b9e299dd2c166a7f090" - }, - "plugins": {} - } - }, - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0x5e3618cFF8Ab337b3c73c2775d1a2EC65e5abEF0", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMNg1a7HvNWuHAPMdveWr1J6NNCVBU1Z4w5swzepT5Wvf", - "publicKey": "abb750e04bee21d830c6ce0f08180853466139fc6055c6737614797c0704d59c" - }, - "ocrKeyBundle": { - "bundleID": "0d176a4c2d68c619d237e419c31a030e5b2162ee031baa8ebc8472623da9b067", - "configPublicKey": "43e4dbf80a9c818a7d35c080f61b6f8f9b175fa1217b1d01168140da75322d5c", - "offchainPublicKey": "707db88237aaaaddc22bf0fe914540ea7b8bbfbe5cf88349cabb26e34762237c", - "onchainSigningAddress": "ac08f52ec257ddbb493e7b9e299dd2c166a7f090" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0x1796BbC2AbbAd5660C8a7812b313E1f48A99f1D1", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMNg1a7HvNWuHAPMdveWr1J6NNCVBU1Z4w5swzepT5Wvf", - "publicKey": "abb750e04bee21d830c6ce0f08180853466139fc6055c6737614797c0704d59c" - }, - "ocrKeyBundle": { - "bundleID": "0d176a4c2d68c619d237e419c31a030e5b2162ee031baa8ebc8472623da9b067", - "configPublicKey": "43e4dbf80a9c818a7d35c080f61b6f8f9b175fa1217b1d01168140da75322d5c", - "offchainPublicKey": "707db88237aaaaddc22bf0fe914540ea7b8bbfbe5cf88349cabb26e34762237c", - "onchainSigningAddress": "ac08f52ec257ddbb493e7b9e299dd2c166a7f090" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xA2bfAc45e6878fbE04525C23dFbb11fFb224Ea60", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMNg1a7HvNWuHAPMdveWr1J6NNCVBU1Z4w5swzepT5Wvf", - "publicKey": "abb750e04bee21d830c6ce0f08180853466139fc6055c6737614797c0704d59c" - }, - "ocrKeyBundle": { - "bundleID": "0d176a4c2d68c619d237e419c31a030e5b2162ee031baa8ebc8472623da9b067", - "configPublicKey": "43e4dbf80a9c818a7d35c080f61b6f8f9b175fa1217b1d01168140da75322d5c", - "offchainPublicKey": "707db88237aaaaddc22bf0fe914540ea7b8bbfbe5cf88349cabb26e34762237c", - "onchainSigningAddress": "ac08f52ec257ddbb493e7b9e299dd2c166a7f090" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:42:05.709664Z" - }, - { - "id": "76", - "keys": [ - "keystone-00", - "keystone-bt-00" - ], - "name": "Chainlink Keystone Node Operator 0", - "metadata": { - "nodeCount": 3, - "jobCount": 5 - }, - "nodes": [ - { - "id": "789", - "name": "Chainlink Sepolia Prod Keystone One 0", - "publicKey": "403b72f0b1b3b5f5a91bcfedb7f28599767502a04b5b7e067fcf3782e23eeb9c", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x1a04C6b4b1A45D20356F93DcE7931F765955BAa7", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMWUKdoAc2ruZf9f55p7NVFj7AFiPm67xjQ8BZBwkqyYv", - "publicKey": "adb6bf005cdb23f21e11b82d66b9f62628c2939640ed93028bf0dad3923c5a8b" - }, - "ocrKeyBundle": { - "bundleID": "665a101d79d310cb0a5ebf695b06e8fc8082b5cbe62d7d362d80d47447a31fea", - "configPublicKey": "5193f72fc7b4323a86088fb0acb4e4494ae351920b3944bd726a59e8dbcdd45f", - "offchainPublicKey": "03dacd15fc96c965c648e3623180de002b71a97cf6eeca9affb91f461dcd6ce1", - "onchainSigningAddress": "b35409a8d4f9a18da55c5b2bb08a3f5f68d44442" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x2877F08d9c5Cc9F401F730Fa418fAE563A9a2FF3", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMWUKdoAc2ruZf9f55p7NVFj7AFiPm67xjQ8BZBwkqyYv", - "publicKey": "adb6bf005cdb23f21e11b82d66b9f62628c2939640ed93028bf0dad3923c5a8b" - }, - "ocrKeyBundle": { - "bundleID": "665a101d79d310cb0a5ebf695b06e8fc8082b5cbe62d7d362d80d47447a31fea", - "configPublicKey": "5193f72fc7b4323a86088fb0acb4e4494ae351920b3944bd726a59e8dbcdd45f", - "offchainPublicKey": "03dacd15fc96c965c648e3623180de002b71a97cf6eeca9affb91f461dcd6ce1", - "onchainSigningAddress": "b35409a8d4f9a18da55c5b2bb08a3f5f68d44442" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - }, - { - "id": "809", - "name": "Chainlink Sepolia Prod Keystone Cap One 0", - "publicKey": "545197637db59b96b22528ff90960b9e7cdcea81c8a5a9f06ae6b728bcba35cb", - "chainConfigs": [ - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0x66a88b0a23D8351e8F5e228eEe8439e65F423842", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWFux8Vvs8CPfUSKitXwQsq81ZBhQYcbKRH5L5jkFbQ6nH", - "publicKey": "5a946cfec8e3c33f6c88961dcab2bbd8bb9d05538c8f931bb62d59b1d7fd782e" - }, - "ocrKeyBundle": { - "bundleID": "d9a3c3afdb310ba11b058afd6ee3159edfbc740df4daefd65c257a7ed46ed9ef", - "configPublicKey": "64fd95e7bcbb33e3dd548247352bb7be5ea6577a840e5e3b66336f710b5b272e", - "offchainPublicKey": "216b1e3dc51ad21be806c010397cc2e0bf59b2a06ade89bc7d0c0a7299a4e01e", - "onchainSigningAddress": "a4f0acbe902443aa842db278f421da99cdc47a8b" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x36a46774A3743641D4C274b385608Cb455B5B6b8", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWFux8Vvs8CPfUSKitXwQsq81ZBhQYcbKRH5L5jkFbQ6nH", - "publicKey": "5a946cfec8e3c33f6c88961dcab2bbd8bb9d05538c8f931bb62d59b1d7fd782e" - }, - "ocrKeyBundle": { - "bundleID": "d9a3c3afdb310ba11b058afd6ee3159edfbc740df4daefd65c257a7ed46ed9ef", - "configPublicKey": "64fd95e7bcbb33e3dd548247352bb7be5ea6577a840e5e3b66336f710b5b272e", - "offchainPublicKey": "216b1e3dc51ad21be806c010397cc2e0bf59b2a06ade89bc7d0c0a7299a4e01e", - "onchainSigningAddress": "a4f0acbe902443aa842db278f421da99cdc47a8b" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0x868ab67c00fF7e21aFf470C066798e5bE4240305", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWFux8Vvs8CPfUSKitXwQsq81ZBhQYcbKRH5L5jkFbQ6nH", - "publicKey": "5a946cfec8e3c33f6c88961dcab2bbd8bb9d05538c8f931bb62d59b1d7fd782e" - }, - "ocrKeyBundle": { - "bundleID": "d9a3c3afdb310ba11b058afd6ee3159edfbc740df4daefd65c257a7ed46ed9ef", - "configPublicKey": "64fd95e7bcbb33e3dd548247352bb7be5ea6577a840e5e3b66336f710b5b272e", - "offchainPublicKey": "216b1e3dc51ad21be806c010397cc2e0bf59b2a06ade89bc7d0c0a7299a4e01e", - "onchainSigningAddress": "a4f0acbe902443aa842db278f421da99cdc47a8b" - }, - "plugins": {} - } - }, - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xa60bC482fCfcd12B752541a00555E4e448Bc1d16", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWFux8Vvs8CPfUSKitXwQsq81ZBhQYcbKRH5L5jkFbQ6nH", - "publicKey": "5a946cfec8e3c33f6c88961dcab2bbd8bb9d05538c8f931bb62d59b1d7fd782e" - }, - "ocrKeyBundle": { - "bundleID": "d9a3c3afdb310ba11b058afd6ee3159edfbc740df4daefd65c257a7ed46ed9ef", - "configPublicKey": "64fd95e7bcbb33e3dd548247352bb7be5ea6577a840e5e3b66336f710b5b272e", - "offchainPublicKey": "216b1e3dc51ad21be806c010397cc2e0bf59b2a06ade89bc7d0c0a7299a4e01e", - "onchainSigningAddress": "a4f0acbe902443aa842db278f421da99cdc47a8b" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:42:49.446864Z" - }, - { - "id": "81", - "keys": [ - "cl-df-asset-don-testnet-0" - ], - "name": "Chainlink Keystone Asset DON Node Operator 0", - "metadata": { - "nodeCount": 2, - "jobCount": 18 - }, - "nodes": [ - { - "id": "831", - "name": "Chainlink Sepolia Prod Keystone Asset Node 0", - "publicKey": "d791dad33f1aeff811f3364088993053d5d08fa595ba48f73aecd4ee2d5035a1", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xe826b8D7f57b1c08E2d0C9477006244AECB280c3", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWDh47EiK5TzG4yApEEwLecgRkqZKQif3fcnsztfhQNzNh", - "publicKey": "398f42d12c7f3445341e42ce4ea555c87d84db68c808c76a0655e5d993d7a2a6" - }, - "ocrKeyBundle": { - "bundleID": "c8dee638c00194cf38bd0c30306fffd14b561601828085ceaaf0ab5fe451ec23", - "configPublicKey": "dbd5d1f5aa4921fd1e7b16f26dc75aff5cc08fee6e74324e947654ba78791e7e", - "offchainPublicKey": "66a599cda37e6fb5dc50e16d7c81e6967e010a25bbeaabf20752e228a26f5bc3", - "onchainSigningAddress": "9184c1c20da57f2f747a60909d0152c289e8518f" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:19:34.127102Z" - }, - { - "id": "82", - "keys": [ - "cl-df-asset-don-testnet-1" - ], - "name": "Chainlink Keystone Asset DON Node Operator 1", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "832", - "name": "Chainlink Sepolia Prod Keystone Asset Node 1", - "publicKey": "eb410038ba7847a729c4e40c1d4afdbcce9ad33cc71e459883cd98f0883a5366", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xCE154165b0d60D1efA9b3c7a172ED77712Cb82f9", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWG7WEsQjxXQdn5WAEQSDh77qxjMoWxz3rGYrRC9pPB7qx", - "publicKey": "5d8a1f11ecd0cd2cdd95fec35b8ea6386af567bc96aa2c2ea47e91d22b1f12bf" - }, - "ocrKeyBundle": { - "bundleID": "a6dda044db7fa1fa652ec9ff60a44fb31ee99d33db35599848b21e34ce33c343", - "configPublicKey": "586fb9935401e8907ead91e7a3423a0c0676d4669bac619f71c99913e14b362a", - "offchainPublicKey": "9557c0c4c6c8aeb41ecaa84f0aa7d0e1be7ffa9e4a08da27b23bd64b2d0c0fe9", - "onchainSigningAddress": "bd3e16dda612f543c0f79fafc03fa35f3f300e30" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:19:48.159926Z" - }, - { - "id": "83", - "keys": [ - "cl-df-asset-don-testnet-2" - ], - "name": "Chainlink Keystone Asset DON Node Operator 2", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "833", - "name": "Chainlink Sepolia Prod Keystone Asset Node 2", - "publicKey": "daf14b79caa585c3dacf550688aeed5371f8fd39cbfb6e33add2fb82538626b0", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xbb16a69A7bb8778dc52a2D081EE1B2Dde0237F3b", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWBWms38viHaptUHTXXNdN4Qm2ZxDWtuaZviZtq1WzWWcq", - "publicKey": "1935b60309f79e7fd1bfd4736df5729b7532bcd435be2a707dd28519e9ae6e6a" - }, - "ocrKeyBundle": { - "bundleID": "9c63a332ff254cd2cda8bcf2c3f0e46ee95d4991595019619a0c60907437d98c", - "configPublicKey": "29b9b6f61db8e72df13e17e274bdf5450987953079b9dee2745f2d288dc7e86d", - "offchainPublicKey": "c3b08d0b68baf68da2c8446f6a9dc552af3ab2014b900d75ca9e2122b6fc9eb0", - "onchainSigningAddress": "cb66494d66922ad00708bce7c83ada133ddb8994" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:20:01.151494Z" - }, - { - "id": "84", - "keys": [ - "cl-df-asset-don-testnet-3" - ], - "name": "Chainlink Keystone Asset DON Node Operator 3", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "834", - "name": "Chainlink Sepolia Prod Keystone Asset Node 3", - "publicKey": "0e1f9462a8b326d746fde2d5016faa9f2e017f7e6e5969aaf3281519d2e31dbc", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xA64f65e0c12ab015792c34867BE5b80b4D4C551A", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMhHZTVHz23gCQAEzFyeBLxR9ghVqMQHk18VND4TbAc1U", - "publicKey": "b07bf77b2b1d8964915d4871b4cd0173e13bc1d0590731a8969393a6e80aef8f" - }, - "ocrKeyBundle": { - "bundleID": "87770ad41d54661a6dee424612f4338b49cd4fd20bdab1f11c308c76efeb56f8", - "configPublicKey": "dd0edc91d1476a0a4c554e8fe8050dadba679ba42f53973bf181d85eed1b6821", - "offchainPublicKey": "2ba2cc779c8e1460d9ff823d594708a344bb7a9d84aa3aa3833d539852511a88", - "onchainSigningAddress": "5e5b1a602c5a79ec6cdeb67e6f855d58061f785f" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:20:10.382565Z" - }, - { - "id": "85", - "keys": [ - "cl-df-asset-don-testnet-4" - ], - "name": "Chainlink Keystone Asset DON Node Operator 4", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "835", - "name": "Chainlink Sepolia Prod Keystone Asset Node 4", - "publicKey": "1d5f6ef3443e48bd471efdb47a5b9c6c900a14f35253c2b562908186f5b8b457", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x7284bBa5C8090Ac99d55b14db015a291C017275c", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMrkkbkFYJydLhcYKr8AnxNcNGmwfVXMQGdn8uoSpYoJs", - "publicKey": "b2e8f0b25c7334e8082cb82eee29bc4f48ae086b8fe4a2fd5eb4e08195a0e06c" - }, - "ocrKeyBundle": { - "bundleID": "1ceac31d893d21e95a62419d94b1a88805fa4f056b1636ccd79ab0ca8b4fe68c", - "configPublicKey": "4c94f49461fd0fd9d4da5cda4590a2cf80fba2ea27c422b92ee18a3aaaa51321", - "offchainPublicKey": "d1649b393614e01811979340d2726280f9ea57fd7a1ee28958adbbaf71b41bf5", - "onchainSigningAddress": "e47d17607054e9899d3fb7fa5b4b3e01b85b8fc9" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:20:21.050174Z" - }, - { - "id": "86", - "keys": [ - "cl-df-asset-don-testnet-5" - ], - "name": "Chainlink Keystone Asset DON Node Operator 5", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "837", - "name": "Chainlink Sepolia Prod Keystone Asset Node 5", - "publicKey": "d87dfbb7444036e0654578afdb11864e31a0de1824ca2780f24b16116a85463d", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x6c75DB65540ca889803a092d4C1497D3337cDE30", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWH8q69DtEqahJdwKfYXnkRHHH6E4jTqevZSAZzGsrnsTB", - "publicKey": "6cbcb3cc0a48ec9d94bb1424beea5e1b7cf57fda2dbfc519afd9221cbeac3b8e" - }, - "ocrKeyBundle": { - "bundleID": "6e088c00e61fea95a5a808a56e7e55c58ec0d61c3207383a2c63abc705bd120c", - "configPublicKey": "0728ce40c95155853ecd31bc213ed2b39d4ecf2e62dc95334f008181ad010848", - "offchainPublicKey": "521d4c291fe8ef245b2e497982b0a07127cd3c65439a10784d914e03ba24328d", - "onchainSigningAddress": "d32a6ed4be6656fd988a0e43e71ce43fab3faba4" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:21:21.831183Z" - }, - { - "id": "87", - "keys": [ - "cl-df-asset-don-testnet-6" - ], - "name": "Chainlink Keystone Asset DON Node Operator 6", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "838", - "name": "Chainlink Sepolia Prod Keystone Asset Node 6", - "publicKey": "294f58723d4049af0dcd63eedfcda957287401a10070db509ede7a799bb70654", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xa2788731913cc2deBC061F8594AEaa8e99B4FCCE", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWD7URmTzSeotMvEzkJTiFrwUHhcGMBeaS9GY8763Sqqnf", - "publicKey": "30f502f9fb19b54e8644f038f57f9a43582f76b86bace61759fff12886ccf1a8" - }, - "ocrKeyBundle": { - "bundleID": "57bc2a8a62ed96e6aa7b9bbe56f93abeef938a1766cb8a6d18e42ebf71101646", - "configPublicKey": "36c882b0cdcec84aa85f00ea43cd31254406cec84d31f6dded69b4fbb3f17449", - "offchainPublicKey": "46951e1e18cee25cd417b3fa7feb25fb53623a249e1c09491bb978dccc2ea76e", - "onchainSigningAddress": "abcd8be3952a84fb10947dbeb768a255ead58ca2" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:21:34.93501Z" - }, - { - "id": "88", - "keys": [ - "cl-df-asset-don-testnet-7" - ], - "name": "Chainlink Keystone Asset DON Node Operator 7", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "839", - "name": "Chainlink Sepolia Prod Keystone Asset Node 7", - "publicKey": "55b0ec5d90de973c00efce233334a9d3c5a94062ea010575bb248eb6804a9cfe", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x14dAF00DaD855089A6586690d5C1fD2779302736", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWBbo44H5CLACV3yGyDWrtMuSWRdN5sQcDsnPC4WfLr6Jo", - "publicKey": "1a7ef5e7420434fcf06de3d15a0191f7499e00e15427679616ce800779ceb514" - }, - "ocrKeyBundle": { - "bundleID": "f87acde2c1c21e8859d84813034d84a3f3bb1d49596e13ac66731d50750b9436", - "configPublicKey": "e75f21bc1dc6eac12358277caf18a216ed54f8dc84285941ef1f5fb1047f8d5b", - "offchainPublicKey": "c7b86dfbdf31a3b13c44305cd6fc88c402653198201006083414223ffc36950d", - "onchainSigningAddress": "93fbb113f191959f8ab5e052395676e0038f2f1f" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:21:45.063449Z" - }, - { - "id": "89", - "keys": [ - "cl-df-asset-don-testnet-8" - ], - "name": "Chainlink Keystone Asset DON Node Operator 8", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "840", - "name": "Chainlink Sepolia Prod Keystone Asset Node 8", - "publicKey": "8f9f327ac7ad823a0f3297f3505591bcd40adc8fb1309f99874c26663cbd5914", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xb0C0168905C07F00A141494eaeFc0bD9F153fc16", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWGVroAehJh33SBns9MohmctNPZSDh89KRQM1J6TSCnT1v", - "publicKey": "63442493270891409900afd3bb868d03fd07c775bb38c56e56a624b674a68b35" - }, - "ocrKeyBundle": { - "bundleID": "4413e0a3080c3dfa7709b16c3ee68c04359e2dd66d107fd3be6ba7c615c4b3b6", - "configPublicKey": "8f3975b19fc6f02e241119b2132331ed9ed0d19221bd0cfd6f54b5859090a741", - "offchainPublicKey": "f4f182c889668d8951932c49e1ffb1252b8a33a9875d3f19aea7bb805b65c7a6", - "onchainSigningAddress": "b257e9efe637f38b5462a170737571ea0f0e2e05" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:21:55.09098Z" - }, - { - "id": "90", - "keys": [ - "cl-df-asset-don-testnet-9" - ], - "name": "Chainlink Keystone Asset DON Node Operator 9", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "841", - "name": "Chainlink Sepolia Prod Keystone Asset Node 9", - "publicKey": "1d79884071dfec1f39dc62f4868f4a143ae39cb03ad9d14142b184686c2b5a93", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x2F5E08a5b9D893e9dA2d68Ef605fBa6f8Ebfd0cB", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWEBn9tWmMWrSxRZe2VQ56RcSHRUPdcFoD3Ep88wqTT9zP", - "publicKey": "40eb109d9f28e8754dfff419a9175d6714405907413d2f77657355721c3b2bd0" - }, - "ocrKeyBundle": { - "bundleID": "6d4da72b1daad0b9ea47a7daa6cde81c1608b7bd199c05b18b989d10c5d7b99e", - "configPublicKey": "7e1c66bfa23c270770401d0dd739adad5a52827ecb40a0668f7e014d53f38059", - "offchainPublicKey": "712561a10b1f7dd96f0ae0f0d3e6cdf83fdd0837d333cf9bbae0090126ae7f39", - "onchainSigningAddress": "2ef8cea7dae7bd1e876a59a44ca59b89adf8abb4" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:22:09.476108Z" - }, - { - "id": "91", - "keys": [ - "cl-df-asset-don-testnet-10" - ], - "name": "Chainlink Keystone Asset DON Node Operator 10", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "842", - "name": "Chainlink Sepolia Prod Keystone Asset Node 10", - "publicKey": "cf6c47ad934518f5947ce8f1a48c2df8c93bd585788a3a82229fd4d723efa706", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x4794743bB8f159954Efa31642609ebfD4D2b9EdC", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWNXZCbQe4Ao7KEciJGY6Ec4oZLZNGcMTPyZ7XpFhLPyLo", - "publicKey": "bcd987b3b2b20d9effe30598850ddfd33023339dab012c4aee4cdc4246111bfc" - }, - "ocrKeyBundle": { - "bundleID": "a8d9929327d89cfabd8c583d250dfddbc14e947e9253f7471191886ca5197786", - "configPublicKey": "a1a390e756bce818d1786dca6ba3e45013085087e5a3be6253d8bbbd6479255a", - "offchainPublicKey": "76522fec251ce6130c03a816025f2054eb3ac83b7d30347f42b73a77e7b9a511", - "onchainSigningAddress": "179d48901e5e9c3c11dd947c001f8a2ee887c8eb" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:22:30.732346Z" - }, - { - "id": "92", - "keys": [ - "cl-df-asset-don-testnet-11" - ], - "name": "Chainlink Keystone Asset DON Node Operator 11", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "843", - "name": "Chainlink Sepolia Prod Keystone Asset Node 11", - "publicKey": "c239c23670224558a64ea3165eae8d67a17b75b1874fbccf8a4dd98e953820ad", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x27AFd92F391dFD7BA1bbC89e3bd13ceC9A667c11", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWSSzLfwq7QSdJcpDLFiBznA1XR58dwg1xre4b88SbP7VF", - "publicKey": "f71ccc7f7b73f1499f72987679a94a11e8564f01415acdb958c008c5bfe21eae" - }, - "ocrKeyBundle": { - "bundleID": "3e691b13aa702631fba25f6e128a566bdff3982cc3438af29acc2a819b9d6e02", - "configPublicKey": "149d81dce137d0874b477ad6c19dc72801f335200622fa34f1c660623febed22", - "offchainPublicKey": "b0d0d8e3c62abc7236e6539413ef82e568dd24f0c39ff6e8e2babe513590a522", - "onchainSigningAddress": "a0f2feab4d03899eb2e830bd4abc3fd5babef3e1" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:22:42.314654Z" - }, - { - "id": "93", - "keys": [ - "cl-df-asset-don-testnet-12" - ], - "name": "Chainlink Keystone Asset DON Node Operator 12", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "844", - "name": "Chainlink Sepolia Prod Keystone Asset Node 12", - "publicKey": "71b29eb63daa6ac2e48b46669936eff5606879b102bae78afc929554c435dd0b", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x13d5b27d71B4C4697874177Ff43DEB1884Cff49e", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWT1LMqEW51UfxBynzjYjuybQzVkmf4rH9js9e16QAbU3X", - "publicKey": "ff66057a6c96779134a6527364cddcce43b69e3d1820f59dde5e6b38d1d32fde" - }, - "ocrKeyBundle": { - "bundleID": "4854ee3fc7ac4591eea33c5d0d1cefd4ad819d2c374a2f86267a9999228a967a", - "configPublicKey": "470225644f274147b5b80c862a3f3cd7a19fed4ff915e9c18ac80e06003ecc6a", - "offchainPublicKey": "e7d89e196f5f6d92f4c42ab34f9a2f21f3201314be65b819872c4609b87866c7", - "onchainSigningAddress": "c84f2f60ccb1d7e6c6e4ae4bc3cab8bb85db8977" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:22:52.838595Z" - }, - { - "id": "94", - "keys": [ - "cl-df-asset-don-testnet-13" - ], - "name": "Chainlink Keystone Asset DON Node Operator 13", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "845", - "name": "Chainlink Sepolia Prod Keystone Asset Node 13", - "publicKey": "c098264a552125355804b903de06400621f2d1de357c2bed94586727fe8a3502", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x5647A091F2a09915c1C0F6ac95630Be87114881F", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWRjg2KoP6jKVWU2BczeduWsdnfN69tHN2YGEAGtETvc9P", - "publicKey": "ec87467a512f8218bb63f7fcf46cf0b8fd8ebb14bd5f3b670908d505a5af801a" - }, - "ocrKeyBundle": { - "bundleID": "20626049a1e24912a14d186645ba70fea4860efcc987b3ec7c9ddc881b5057db", - "configPublicKey": "d84d4653db0caca062d4058e9937ae618a53bbd1b41a673c5f13bebc24e7aa3a", - "offchainPublicKey": "156c8ab52099386377fe27bbd50dafa368ff2790245f1407579f590b0bae7a1e", - "onchainSigningAddress": "4f4b7bff5d32d62326b575d8c951d34e54888e31" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:23:19.587619Z" - }, - { - "id": "95", - "keys": [ - "cl-df-asset-don-testnet-14" - ], - "name": "Chainlink Keystone Asset DON Node Operator 14", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "846", - "name": "Chainlink Sepolia Prod Keystone Asset Node 14", - "publicKey": "12681ec137cd2d25e7c71638f564404dd764061921c870bbcddf683d048eed21", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x0419E70d32c3972930c99aaaDF20dCB473c56d22", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCdEG68z5kwYuD1xp1aJsFBtpw2HYh1K3ffVM6keVrJnT", - "publicKey": "29b8bafebdef5e11ec3556fbcacdfb626d2f80cf178406e38664775e8b1ace78" - }, - "ocrKeyBundle": { - "bundleID": "80b1304898d5cea3c684790a0f01158468c7fa7770675edef33e4b137232ddc9", - "configPublicKey": "15552ecb6ff10103a534f02594a7b7cbab686d76d5e7b32a9c67059e8c856861", - "offchainPublicKey": "b561b7df3bdfe70f1af9395dbc00ef796774aa352c9a30d9c7e2f7e74d438073", - "onchainSigningAddress": "fb1ca65bf473b4443d7359becc0de67a2d96228d" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:23:44.73219Z" - }, - { - "id": "96", - "keys": [ - "cl-df-asset-don-testnet-15" - ], - "name": "Chainlink Keystone Asset DON Node Operator 15", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "847", - "name": "Chainlink Sepolia Prod Keystone Asset Node 15", - "publicKey": "a9a5d084f9cbbbd291eb43c33dd137cd6140e33c53cebb260463bf52795ec579", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x931900764a585D7a01e500976B630B4747216c8c", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQyZ9A9ScBpcoRww1gJVBNB2brNkjJhaqze6ehuv6bmfQ", - "publicKey": "e139f020ae4bc9efaa77da9cfd54339d36176479028f849b9e64ad2cf29acba3" - }, - "ocrKeyBundle": { - "bundleID": "5c1c69eb1d6619b2c9b93bdfdd9c1b87c28101d6fc88bf7979ad52ceda459908", - "configPublicKey": "33f2107ab22b3dd5c19d5de0c5b1e6e038f2275ba455eed7997485caec421925", - "offchainPublicKey": "bb91b077c135cbdd1f4422c6021cf56d78326710c8bb8c4a87b3e7415e48915f", - "onchainSigningAddress": "b94e3de607033d03e3f0cc3ef1f09edd2592b440" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:24:01.875231Z" - } -] \ No newline at end of file diff --git a/deployment/environment/clo/utils.go b/deployment/environment/clo/utils.go deleted file mode 100644 index 67be141a6db..00000000000 --- a/deployment/environment/clo/utils.go +++ /dev/null @@ -1,101 +0,0 @@ -package clo - -import ( - "fmt" - - jd "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node" - "github.com/smartcontractkit/chainlink/deployment/environment/clo/models" -) - -// NewChainConfig creates a new JobDistributor ChainConfig from a clo model NodeChainConfig -func NewChainConfig(chain *models.NodeChainConfig) *jd.ChainConfig { - return &jd.ChainConfig{ - Chain: &jd.Chain{ - Id: chain.Network.ChainID, - Type: jd.ChainType_CHAIN_TYPE_EVM, // TODO: support other chain types - }, - - AccountAddress: chain.AccountAddress, - AdminAddress: chain.AdminAddress, - Ocr2Config: &jd.OCR2Config{ - Enabled: chain.Ocr2Config.Enabled, - P2PKeyBundle: &jd.OCR2Config_P2PKeyBundle{ - PeerId: chain.Ocr2Config.P2pKeyBundle.PeerID, - PublicKey: chain.Ocr2Config.P2pKeyBundle.PublicKey, - }, - OcrKeyBundle: &jd.OCR2Config_OCRKeyBundle{ - BundleId: chain.Ocr2Config.OcrKeyBundle.BundleID, - OnchainSigningAddress: chain.Ocr2Config.OcrKeyBundle.OnchainSigningAddress, - OffchainPublicKey: chain.Ocr2Config.OcrKeyBundle.OffchainPublicKey, - ConfigPublicKey: chain.Ocr2Config.OcrKeyBundle.ConfigPublicKey, - }, - }, - } -} - -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 deleted file mode 100644 index e2202d4e14f..00000000000 --- a/deployment/environment/clo/utils_test.go +++ /dev/null @@ -1,168 +0,0 @@ -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/keystone/deploy_test.go b/deployment/keystone/deploy_test.go deleted file mode 100644 index eb167ed60fb..00000000000 --- a/deployment/keystone/deploy_test.go +++ /dev/null @@ -1,252 +0,0 @@ -package keystone_test - -import ( - "encoding/json" - "fmt" - "os" - "strconv" - "testing" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - chainsel "github.com/smartcontractkit/chain-selectors" - - "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" - - "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/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -// 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.Test(t) - - 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) - requireChains(t, wfNops, []models.ChainType{models.ChainTypeEvm, models.ChainTypeAptos}) - require.Len(t, cwNops, 10) - requireChains(t, cwNops, []models.ChainType{models.ChainTypeEvm, models.ChainTypeEvm}) - 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: wfNodes, - Capabilities: []kcr.CapabilitiesRegistryCapability{keystone.OCR3Cap}, - } - cwDon := keystone.DonCapabilities{ - Name: keystone.TargetDonName, - Nops: cwNodes, - Capabilities: []kcr.CapabilitiesRegistryCapability{keystone.WriteChainCap}, - } - assetDon := keystone.DonCapabilities{ - Name: keystone.StreamDonName, - Nops: assetNodes, - Capabilities: []kcr.CapabilitiesRegistryCapability{keystone.StreamTriggerCap}, - } - - 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, - OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), - } - // 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) - require.NoError(t, err) - - var ocr3Config = keystone.OracleConfig{ - MaxFaultyOracles: len(wfNops) / 3, - } - - ctx := tests.Context(t) - // explicitly deploy the contracts - cs, err := keystone.DeployContracts(env, registryChainSel) - require.NoError(t, err) - // Deploy successful these are now part of our env. - require.NoError(t, env.ExistingAddresses.Merge(cs.AddressBook)) - - deployReq := keystone.ConfigureContractsRequest{ - RegistryChainSel: registryChainSel, - Env: env, - OCR3Config: &ocr3Config, - Dons: []keystone.DonCapabilities{wfDon, cwDon, assetDon}, - DoContractDeploy: false, - } - deployResp, err := keystone.ConfigureContracts(ctx, lggr, deployReq) - require.NoError(t, err) - ad := env.ExistingAddresses - - // all contracts on home chain - homeChainAddrs, err := ad.AddressesForChain(registryChainSel) - 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 != registryChainSel { - 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[registryChainSel] - require.True(t, ok) - gotRegistry := regChainContracts.CapabilitiesRegistry - require.NotNil(t, gotRegistry) - // check DONs - 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)) - // check NOPs - nops, err := gotRegistry.GetNodeOperators(&bind.CallOpts{}) - if err != nil { - err = keystone.DecodeErr(kcr.CapabilitiesRegistryABI, err) - require.Fail(t, fmt.Sprintf("failed to get NOPs from registry at %s: %s", gotRegistry.Address().String(), err)) - } - require.NoError(t, err) - assert.Len(t, nops, 26) // 10 NOPs owning workflow & writer DONs + 16 NOPs owning Asset DON - - 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 != registryChainSel { - 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) - } -} - -func requireChains(t *testing.T, donNops []*models.NodeOperator, cs []models.ChainType) { - got := make(map[models.ChainType]struct{}) - want := make(map[models.ChainType]struct{}) - for _, c := range cs { - want[c] = struct{}{} - } - for _, nop := range donNops { - for _, node := range nop.Nodes { - for _, cc := range node.ChainConfigs { - got[cc.Network.ChainType] = struct{}{} - } - } - require.EqualValues(t, want, got, "did not find all chains in node %s", nop.Name) - } -} - -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/deployment/keystone/testdata/asset_nodes.json b/deployment/keystone/testdata/asset_nodes.json deleted file mode 100644 index 9ad2ba4e0e8..00000000000 --- a/deployment/keystone/testdata/asset_nodes.json +++ /dev/null @@ -1,978 +0,0 @@ -[ - { - "id": "81", - "keys": [ - "cl-df-asset-don-testnet-0" - ], - "name": "Chainlink Keystone Asset DON Node Operator 0", - "metadata": { - "nodeCount": 2, - "jobCount": 18 - }, - "nodes": [ - { - "id": "831", - "name": "Chainlink Sepolia Prod Keystone Asset Node 0", - "publicKey": "d791dad33f1aeff811f3364088993053d5d08fa595ba48f73aecd4ee2d5035a1", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xe826b8D7f57b1c08E2d0C9477006244AECB280c3", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWDh47EiK5TzG4yApEEwLecgRkqZKQif3fcnsztfhQNzNh", - "publicKey": "398f42d12c7f3445341e42ce4ea555c87d84db68c808c76a0655e5d993d7a2a6" - }, - "ocrKeyBundle": { - "bundleID": "c8dee638c00194cf38bd0c30306fffd14b561601828085ceaaf0ab5fe451ec23", - "configPublicKey": "dbd5d1f5aa4921fd1e7b16f26dc75aff5cc08fee6e74324e947654ba78791e7e", - "offchainPublicKey": "66a599cda37e6fb5dc50e16d7c81e6967e010a25bbeaabf20752e228a26f5bc3", - "onchainSigningAddress": "9184c1c20da57f2f747a60909d0152c289e8518f" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:19:34.127102Z" - }, - { - "id": "82", - "keys": [ - "cl-df-asset-don-testnet-1" - ], - "name": "Chainlink Keystone Asset DON Node Operator 1", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "832", - "name": "Chainlink Sepolia Prod Keystone Asset Node 1", - "publicKey": "eb410038ba7847a729c4e40c1d4afdbcce9ad33cc71e459883cd98f0883a5366", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xCE154165b0d60D1efA9b3c7a172ED77712Cb82f9", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWG7WEsQjxXQdn5WAEQSDh77qxjMoWxz3rGYrRC9pPB7qx", - "publicKey": "5d8a1f11ecd0cd2cdd95fec35b8ea6386af567bc96aa2c2ea47e91d22b1f12bf" - }, - "ocrKeyBundle": { - "bundleID": "a6dda044db7fa1fa652ec9ff60a44fb31ee99d33db35599848b21e34ce33c343", - "configPublicKey": "586fb9935401e8907ead91e7a3423a0c0676d4669bac619f71c99913e14b362a", - "offchainPublicKey": "9557c0c4c6c8aeb41ecaa84f0aa7d0e1be7ffa9e4a08da27b23bd64b2d0c0fe9", - "onchainSigningAddress": "bd3e16dda612f543c0f79fafc03fa35f3f300e30" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:19:48.159926Z" - }, - { - "id": "83", - "keys": [ - "cl-df-asset-don-testnet-2" - ], - "name": "Chainlink Keystone Asset DON Node Operator 2", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "833", - "name": "Chainlink Sepolia Prod Keystone Asset Node 2", - "publicKey": "daf14b79caa585c3dacf550688aeed5371f8fd39cbfb6e33add2fb82538626b0", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xbb16a69A7bb8778dc52a2D081EE1B2Dde0237F3b", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWBWms38viHaptUHTXXNdN4Qm2ZxDWtuaZviZtq1WzWWcq", - "publicKey": "1935b60309f79e7fd1bfd4736df5729b7532bcd435be2a707dd28519e9ae6e6a" - }, - "ocrKeyBundle": { - "bundleID": "9c63a332ff254cd2cda8bcf2c3f0e46ee95d4991595019619a0c60907437d98c", - "configPublicKey": "29b9b6f61db8e72df13e17e274bdf5450987953079b9dee2745f2d288dc7e86d", - "offchainPublicKey": "c3b08d0b68baf68da2c8446f6a9dc552af3ab2014b900d75ca9e2122b6fc9eb0", - "onchainSigningAddress": "cb66494d66922ad00708bce7c83ada133ddb8994" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:20:01.151494Z" - }, - { - "id": "84", - "keys": [ - "cl-df-asset-don-testnet-3" - ], - "name": "Chainlink Keystone Asset DON Node Operator 3", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "834", - "name": "Chainlink Sepolia Prod Keystone Asset Node 3", - "publicKey": "0e1f9462a8b326d746fde2d5016faa9f2e017f7e6e5969aaf3281519d2e31dbc", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xA64f65e0c12ab015792c34867BE5b80b4D4C551A", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMhHZTVHz23gCQAEzFyeBLxR9ghVqMQHk18VND4TbAc1U", - "publicKey": "b07bf77b2b1d8964915d4871b4cd0173e13bc1d0590731a8969393a6e80aef8f" - }, - "ocrKeyBundle": { - "bundleID": "87770ad41d54661a6dee424612f4338b49cd4fd20bdab1f11c308c76efeb56f8", - "configPublicKey": "dd0edc91d1476a0a4c554e8fe8050dadba679ba42f53973bf181d85eed1b6821", - "offchainPublicKey": "2ba2cc779c8e1460d9ff823d594708a344bb7a9d84aa3aa3833d539852511a88", - "onchainSigningAddress": "5e5b1a602c5a79ec6cdeb67e6f855d58061f785f" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:20:10.382565Z" - }, - { - "id": "85", - "keys": [ - "cl-df-asset-don-testnet-4" - ], - "name": "Chainlink Keystone Asset DON Node Operator 4", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "835", - "name": "Chainlink Sepolia Prod Keystone Asset Node 4", - "publicKey": "1d5f6ef3443e48bd471efdb47a5b9c6c900a14f35253c2b562908186f5b8b457", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x7284bBa5C8090Ac99d55b14db015a291C017275c", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMrkkbkFYJydLhcYKr8AnxNcNGmwfVXMQGdn8uoSpYoJs", - "publicKey": "b2e8f0b25c7334e8082cb82eee29bc4f48ae086b8fe4a2fd5eb4e08195a0e06c" - }, - "ocrKeyBundle": { - "bundleID": "1ceac31d893d21e95a62419d94b1a88805fa4f056b1636ccd79ab0ca8b4fe68c", - "configPublicKey": "4c94f49461fd0fd9d4da5cda4590a2cf80fba2ea27c422b92ee18a3aaaa51321", - "offchainPublicKey": "d1649b393614e01811979340d2726280f9ea57fd7a1ee28958adbbaf71b41bf5", - "onchainSigningAddress": "e47d17607054e9899d3fb7fa5b4b3e01b85b8fc9" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:20:21.050174Z" - }, - { - "id": "86", - "keys": [ - "cl-df-asset-don-testnet-5" - ], - "name": "Chainlink Keystone Asset DON Node Operator 5", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "837", - "name": "Chainlink Sepolia Prod Keystone Asset Node 5", - "publicKey": "d87dfbb7444036e0654578afdb11864e31a0de1824ca2780f24b16116a85463d", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x6c75DB65540ca889803a092d4C1497D3337cDE30", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWH8q69DtEqahJdwKfYXnkRHHH6E4jTqevZSAZzGsrnsTB", - "publicKey": "6cbcb3cc0a48ec9d94bb1424beea5e1b7cf57fda2dbfc519afd9221cbeac3b8e" - }, - "ocrKeyBundle": { - "bundleID": "6e088c00e61fea95a5a808a56e7e55c58ec0d61c3207383a2c63abc705bd120c", - "configPublicKey": "0728ce40c95155853ecd31bc213ed2b39d4ecf2e62dc95334f008181ad010848", - "offchainPublicKey": "521d4c291fe8ef245b2e497982b0a07127cd3c65439a10784d914e03ba24328d", - "onchainSigningAddress": "d32a6ed4be6656fd988a0e43e71ce43fab3faba4" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:21:21.831183Z" - }, - { - "id": "87", - "keys": [ - "cl-df-asset-don-testnet-6" - ], - "name": "Chainlink Keystone Asset DON Node Operator 6", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "838", - "name": "Chainlink Sepolia Prod Keystone Asset Node 6", - "publicKey": "294f58723d4049af0dcd63eedfcda957287401a10070db509ede7a799bb70654", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xa2788731913cc2deBC061F8594AEaa8e99B4FCCE", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWD7URmTzSeotMvEzkJTiFrwUHhcGMBeaS9GY8763Sqqnf", - "publicKey": "30f502f9fb19b54e8644f038f57f9a43582f76b86bace61759fff12886ccf1a8" - }, - "ocrKeyBundle": { - "bundleID": "57bc2a8a62ed96e6aa7b9bbe56f93abeef938a1766cb8a6d18e42ebf71101646", - "configPublicKey": "36c882b0cdcec84aa85f00ea43cd31254406cec84d31f6dded69b4fbb3f17449", - "offchainPublicKey": "46951e1e18cee25cd417b3fa7feb25fb53623a249e1c09491bb978dccc2ea76e", - "onchainSigningAddress": "abcd8be3952a84fb10947dbeb768a255ead58ca2" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:21:34.93501Z" - }, - { - "id": "88", - "keys": [ - "cl-df-asset-don-testnet-7" - ], - "name": "Chainlink Keystone Asset DON Node Operator 7", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "839", - "name": "Chainlink Sepolia Prod Keystone Asset Node 7", - "publicKey": "55b0ec5d90de973c00efce233334a9d3c5a94062ea010575bb248eb6804a9cfe", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x14dAF00DaD855089A6586690d5C1fD2779302736", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWBbo44H5CLACV3yGyDWrtMuSWRdN5sQcDsnPC4WfLr6Jo", - "publicKey": "1a7ef5e7420434fcf06de3d15a0191f7499e00e15427679616ce800779ceb514" - }, - "ocrKeyBundle": { - "bundleID": "f87acde2c1c21e8859d84813034d84a3f3bb1d49596e13ac66731d50750b9436", - "configPublicKey": "e75f21bc1dc6eac12358277caf18a216ed54f8dc84285941ef1f5fb1047f8d5b", - "offchainPublicKey": "c7b86dfbdf31a3b13c44305cd6fc88c402653198201006083414223ffc36950d", - "onchainSigningAddress": "93fbb113f191959f8ab5e052395676e0038f2f1f" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:21:45.063449Z" - }, - { - "id": "89", - "keys": [ - "cl-df-asset-don-testnet-8" - ], - "name": "Chainlink Keystone Asset DON Node Operator 8", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "840", - "name": "Chainlink Sepolia Prod Keystone Asset Node 8", - "publicKey": "8f9f327ac7ad823a0f3297f3505591bcd40adc8fb1309f99874c26663cbd5914", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xb0C0168905C07F00A141494eaeFc0bD9F153fc16", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWGVroAehJh33SBns9MohmctNPZSDh89KRQM1J6TSCnT1v", - "publicKey": "63442493270891409900afd3bb868d03fd07c775bb38c56e56a624b674a68b35" - }, - "ocrKeyBundle": { - "bundleID": "4413e0a3080c3dfa7709b16c3ee68c04359e2dd66d107fd3be6ba7c615c4b3b6", - "configPublicKey": "8f3975b19fc6f02e241119b2132331ed9ed0d19221bd0cfd6f54b5859090a741", - "offchainPublicKey": "f4f182c889668d8951932c49e1ffb1252b8a33a9875d3f19aea7bb805b65c7a6", - "onchainSigningAddress": "b257e9efe637f38b5462a170737571ea0f0e2e05" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:21:55.09098Z" - }, - { - "id": "90", - "keys": [ - "cl-df-asset-don-testnet-9" - ], - "name": "Chainlink Keystone Asset DON Node Operator 9", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "841", - "name": "Chainlink Sepolia Prod Keystone Asset Node 9", - "publicKey": "1d79884071dfec1f39dc62f4868f4a143ae39cb03ad9d14142b184686c2b5a93", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x2F5E08a5b9D893e9dA2d68Ef605fBa6f8Ebfd0cB", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWEBn9tWmMWrSxRZe2VQ56RcSHRUPdcFoD3Ep88wqTT9zP", - "publicKey": "40eb109d9f28e8754dfff419a9175d6714405907413d2f77657355721c3b2bd0" - }, - "ocrKeyBundle": { - "bundleID": "6d4da72b1daad0b9ea47a7daa6cde81c1608b7bd199c05b18b989d10c5d7b99e", - "configPublicKey": "7e1c66bfa23c270770401d0dd739adad5a52827ecb40a0668f7e014d53f38059", - "offchainPublicKey": "712561a10b1f7dd96f0ae0f0d3e6cdf83fdd0837d333cf9bbae0090126ae7f39", - "onchainSigningAddress": "2ef8cea7dae7bd1e876a59a44ca59b89adf8abb4" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:22:09.476108Z" - }, - { - "id": "91", - "keys": [ - "cl-df-asset-don-testnet-10" - ], - "name": "Chainlink Keystone Asset DON Node Operator 10", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "842", - "name": "Chainlink Sepolia Prod Keystone Asset Node 10", - "publicKey": "cf6c47ad934518f5947ce8f1a48c2df8c93bd585788a3a82229fd4d723efa706", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x4794743bB8f159954Efa31642609ebfD4D2b9EdC", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWNXZCbQe4Ao7KEciJGY6Ec4oZLZNGcMTPyZ7XpFhLPyLo", - "publicKey": "bcd987b3b2b20d9effe30598850ddfd33023339dab012c4aee4cdc4246111bfc" - }, - "ocrKeyBundle": { - "bundleID": "a8d9929327d89cfabd8c583d250dfddbc14e947e9253f7471191886ca5197786", - "configPublicKey": "a1a390e756bce818d1786dca6ba3e45013085087e5a3be6253d8bbbd6479255a", - "offchainPublicKey": "76522fec251ce6130c03a816025f2054eb3ac83b7d30347f42b73a77e7b9a511", - "onchainSigningAddress": "179d48901e5e9c3c11dd947c001f8a2ee887c8eb" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:22:30.732346Z" - }, - { - "id": "92", - "keys": [ - "cl-df-asset-don-testnet-11" - ], - "name": "Chainlink Keystone Asset DON Node Operator 11", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "843", - "name": "Chainlink Sepolia Prod Keystone Asset Node 11", - "publicKey": "c239c23670224558a64ea3165eae8d67a17b75b1874fbccf8a4dd98e953820ad", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x27AFd92F391dFD7BA1bbC89e3bd13ceC9A667c11", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWSSzLfwq7QSdJcpDLFiBznA1XR58dwg1xre4b88SbP7VF", - "publicKey": "f71ccc7f7b73f1499f72987679a94a11e8564f01415acdb958c008c5bfe21eae" - }, - "ocrKeyBundle": { - "bundleID": "3e691b13aa702631fba25f6e128a566bdff3982cc3438af29acc2a819b9d6e02", - "configPublicKey": "149d81dce137d0874b477ad6c19dc72801f335200622fa34f1c660623febed22", - "offchainPublicKey": "b0d0d8e3c62abc7236e6539413ef82e568dd24f0c39ff6e8e2babe513590a522", - "onchainSigningAddress": "a0f2feab4d03899eb2e830bd4abc3fd5babef3e1" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:22:42.314654Z" - }, - { - "id": "93", - "keys": [ - "cl-df-asset-don-testnet-12" - ], - "name": "Chainlink Keystone Asset DON Node Operator 12", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "844", - "name": "Chainlink Sepolia Prod Keystone Asset Node 12", - "publicKey": "71b29eb63daa6ac2e48b46669936eff5606879b102bae78afc929554c435dd0b", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x13d5b27d71B4C4697874177Ff43DEB1884Cff49e", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWT1LMqEW51UfxBynzjYjuybQzVkmf4rH9js9e16QAbU3X", - "publicKey": "ff66057a6c96779134a6527364cddcce43b69e3d1820f59dde5e6b38d1d32fde" - }, - "ocrKeyBundle": { - "bundleID": "4854ee3fc7ac4591eea33c5d0d1cefd4ad819d2c374a2f86267a9999228a967a", - "configPublicKey": "470225644f274147b5b80c862a3f3cd7a19fed4ff915e9c18ac80e06003ecc6a", - "offchainPublicKey": "e7d89e196f5f6d92f4c42ab34f9a2f21f3201314be65b819872c4609b87866c7", - "onchainSigningAddress": "c84f2f60ccb1d7e6c6e4ae4bc3cab8bb85db8977" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:22:52.838595Z" - }, - { - "id": "94", - "keys": [ - "cl-df-asset-don-testnet-13" - ], - "name": "Chainlink Keystone Asset DON Node Operator 13", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "845", - "name": "Chainlink Sepolia Prod Keystone Asset Node 13", - "publicKey": "c098264a552125355804b903de06400621f2d1de357c2bed94586727fe8a3502", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x5647A091F2a09915c1C0F6ac95630Be87114881F", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWRjg2KoP6jKVWU2BczeduWsdnfN69tHN2YGEAGtETvc9P", - "publicKey": "ec87467a512f8218bb63f7fcf46cf0b8fd8ebb14bd5f3b670908d505a5af801a" - }, - "ocrKeyBundle": { - "bundleID": "20626049a1e24912a14d186645ba70fea4860efcc987b3ec7c9ddc881b5057db", - "configPublicKey": "d84d4653db0caca062d4058e9937ae618a53bbd1b41a673c5f13bebc24e7aa3a", - "offchainPublicKey": "156c8ab52099386377fe27bbd50dafa368ff2790245f1407579f590b0bae7a1e", - "onchainSigningAddress": "4f4b7bff5d32d62326b575d8c951d34e54888e31" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:23:19.587619Z" - }, - { - "id": "95", - "keys": [ - "cl-df-asset-don-testnet-14" - ], - "name": "Chainlink Keystone Asset DON Node Operator 14", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "846", - "name": "Chainlink Sepolia Prod Keystone Asset Node 14", - "publicKey": "12681ec137cd2d25e7c71638f564404dd764061921c870bbcddf683d048eed21", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x0419E70d32c3972930c99aaaDF20dCB473c56d22", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCdEG68z5kwYuD1xp1aJsFBtpw2HYh1K3ffVM6keVrJnT", - "publicKey": "29b8bafebdef5e11ec3556fbcacdfb626d2f80cf178406e38664775e8b1ace78" - }, - "ocrKeyBundle": { - "bundleID": "80b1304898d5cea3c684790a0f01158468c7fa7770675edef33e4b137232ddc9", - "configPublicKey": "15552ecb6ff10103a534f02594a7b7cbab686d76d5e7b32a9c67059e8c856861", - "offchainPublicKey": "b561b7df3bdfe70f1af9395dbc00ef796774aa352c9a30d9c7e2f7e74d438073", - "onchainSigningAddress": "fb1ca65bf473b4443d7359becc0de67a2d96228d" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:23:44.73219Z" - }, - { - "id": "96", - "keys": [ - "cl-df-asset-don-testnet-15" - ], - "name": "Chainlink Keystone Asset DON Node Operator 15", - "metadata": { - "nodeCount": 1, - "jobCount": 9 - }, - "nodes": [ - { - "id": "847", - "name": "Chainlink Sepolia Prod Keystone Asset Node 15", - "publicKey": "a9a5d084f9cbbbd291eb43c33dd137cd6140e33c53cebb260463bf52795ec579", - "chainConfigs": [ - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x931900764a585D7a01e500976B630B4747216c8c", - "adminAddress": "0x900FDC4d45297A743e4508986d4C1aa1BAf89A83", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQyZ9A9ScBpcoRww1gJVBNB2brNkjJhaqze6ehuv6bmfQ", - "publicKey": "e139f020ae4bc9efaa77da9cfd54339d36176479028f849b9e64ad2cf29acba3" - }, - "ocrKeyBundle": { - "bundleID": "5c1c69eb1d6619b2c9b93bdfdd9c1b87c28101d6fc88bf7979ad52ceda459908", - "configPublicKey": "33f2107ab22b3dd5c19d5de0c5b1e6e038f2275ba455eed7997485caec421925", - "offchainPublicKey": "bb91b077c135cbdd1f4422c6021cf56d78326710c8bb8c4a87b3e7415e48915f", - "onchainSigningAddress": "b94e3de607033d03e3f0cc3ef1f09edd2592b440" - }, - "plugins": { - "mercury": true - } - } - } - ], - "connected": true, - "supportedProducts": [ - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-09-18T19:24:01.875231Z" - } -] diff --git a/deployment/keystone/testdata/chain_writer_nodes.json b/deployment/keystone/testdata/chain_writer_nodes.json deleted file mode 100644 index 807730451ad..00000000000 --- a/deployment/keystone/testdata/chain_writer_nodes.json +++ /dev/null @@ -1,1447 +0,0 @@ - -[ - { - "id": "67", - "keys": [ - "keystone-09" - ], - "name": "Chainlink Keystone Node Operator 9", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "818", - "name": "Chainlink Sepolia Prod Keystone Cap One 9", - "publicKey": "3f5bbcb4b0409e6ea39d824f1837787484475fffb12e5e4a70509756ef6c7f9a", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x9b74f08bD7269919C0597C0E00e70ef2A66829db", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWPG6X2RgqoSWtM3kvETV6kK4ki8FftaBkwvFWk8yKRBkz", - "publicKey": "c7bf55cf625a55470b0c56c3e51ad175c9dd0d42ca48246c205c715b7495937f" - }, - "ocrKeyBundle": { - "bundleID": "aa717effd7d28374c5980dbd9583dcff5e0800e7100051c6c8418899648dffbf", - "configPublicKey": "3fd95a3839f15adcdff573e6fbf07d06d78fbfeac5eb683f67e70226c1983c44", - "offchainPublicKey": "2b8b8d091c6f4446365f463e6132d699206bbddd38284e8e14ae0443382f297c", - "onchainSigningAddress": "b05b138a987fceffa68f79bdbb36a1faf8d3d964" - }, - "plugins": {} - } - }, - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0x662B6B119f7fc9Dc2A526395A9EA88AE79A1192F", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWPG6X2RgqoSWtM3kvETV6kK4ki8FftaBkwvFWk8yKRBkz", - "publicKey": "c7bf55cf625a55470b0c56c3e51ad175c9dd0d42ca48246c205c715b7495937f" - }, - "ocrKeyBundle": { - "bundleID": "aa717effd7d28374c5980dbd9583dcff5e0800e7100051c6c8418899648dffbf", - "configPublicKey": "3fd95a3839f15adcdff573e6fbf07d06d78fbfeac5eb683f67e70226c1983c44", - "offchainPublicKey": "2b8b8d091c6f4446365f463e6132d699206bbddd38284e8e14ae0443382f297c", - "onchainSigningAddress": "b05b138a987fceffa68f79bdbb36a1faf8d3d964" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0x34431021e0E07c75816226697Af6Ef02725e36af", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWPG6X2RgqoSWtM3kvETV6kK4ki8FftaBkwvFWk8yKRBkz", - "publicKey": "c7bf55cf625a55470b0c56c3e51ad175c9dd0d42ca48246c205c715b7495937f" - }, - "ocrKeyBundle": { - "bundleID": "aa717effd7d28374c5980dbd9583dcff5e0800e7100051c6c8418899648dffbf", - "configPublicKey": "3fd95a3839f15adcdff573e6fbf07d06d78fbfeac5eb683f67e70226c1983c44", - "offchainPublicKey": "2b8b8d091c6f4446365f463e6132d699206bbddd38284e8e14ae0443382f297c", - "onchainSigningAddress": "b05b138a987fceffa68f79bdbb36a1faf8d3d964" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xB5988d5d9ADd3d98CF45211bE37cf9b3372054C9", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWPG6X2RgqoSWtM3kvETV6kK4ki8FftaBkwvFWk8yKRBkz", - "publicKey": "c7bf55cf625a55470b0c56c3e51ad175c9dd0d42ca48246c205c715b7495937f" - }, - "ocrKeyBundle": { - "bundleID": "aa717effd7d28374c5980dbd9583dcff5e0800e7100051c6c8418899648dffbf", - "configPublicKey": "3fd95a3839f15adcdff573e6fbf07d06d78fbfeac5eb683f67e70226c1983c44", - "offchainPublicKey": "2b8b8d091c6f4446365f463e6132d699206bbddd38284e8e14ae0443382f297c", - "onchainSigningAddress": "b05b138a987fceffa68f79bdbb36a1faf8d3d964" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T19:00:07.113658Z" - }, - { - "id": "68", - "keys": [ - "keystone-08" - ], - "name": "Chainlink Keystone Node Operator 8", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "817", - "name": "Chainlink Sepolia Prod Keystone Cap One 8", - "publicKey": "2346da196a82c88fe6c315d2e4d0dddacf4590a172b20adb6f27a8601ca0540d", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xa5C7133aBD35F9d742bD2997D693A507c5eBf4Ac", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWNfg9cYxEri1zGbdCZ87DekmruYY6J1wUobEwNNVewMpT", - "publicKey": "beee088bccea272eb6473fcc1cd3e22f2fc8d3a253a6398b69f5aab94070e690" - }, - "ocrKeyBundle": { - "bundleID": "9fba2d29874bb06b07272bd9141f096c1987d790bb0f81c3ffaf66d11cdac4f2", - "configPublicKey": "66dec87065de79e64ed4edd2478ec40a66f955af56e7b837729f464f8487d713", - "offchainPublicKey": "a0f59d50078c77812da8d3077f552209adfb58e76b635e008b6b0f872ce52139", - "onchainSigningAddress": "ed25406f1ef2e1381f6e1e04341f1a6e8b4eacea" - }, - "plugins": {} - } - }, - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0x9fd869f5baADb79F9b7C58c0855fcAc0384e1d4B", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWNfg9cYxEri1zGbdCZ87DekmruYY6J1wUobEwNNVewMpT", - "publicKey": "beee088bccea272eb6473fcc1cd3e22f2fc8d3a253a6398b69f5aab94070e690" - }, - "ocrKeyBundle": { - "bundleID": "9fba2d29874bb06b07272bd9141f096c1987d790bb0f81c3ffaf66d11cdac4f2", - "configPublicKey": "66dec87065de79e64ed4edd2478ec40a66f955af56e7b837729f464f8487d713", - "offchainPublicKey": "a0f59d50078c77812da8d3077f552209adfb58e76b635e008b6b0f872ce52139", - "onchainSigningAddress": "ed25406f1ef2e1381f6e1e04341f1a6e8b4eacea" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0xe477E4C2e335E9b839665d710dE77CFECa9C43A7", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWNfg9cYxEri1zGbdCZ87DekmruYY6J1wUobEwNNVewMpT", - "publicKey": "beee088bccea272eb6473fcc1cd3e22f2fc8d3a253a6398b69f5aab94070e690" - }, - "ocrKeyBundle": { - "bundleID": "9fba2d29874bb06b07272bd9141f096c1987d790bb0f81c3ffaf66d11cdac4f2", - "configPublicKey": "66dec87065de79e64ed4edd2478ec40a66f955af56e7b837729f464f8487d713", - "offchainPublicKey": "a0f59d50078c77812da8d3077f552209adfb58e76b635e008b6b0f872ce52139", - "onchainSigningAddress": "ed25406f1ef2e1381f6e1e04341f1a6e8b4eacea" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x056A1275DD670205aba10D8fC9bB597777a65030", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWNfg9cYxEri1zGbdCZ87DekmruYY6J1wUobEwNNVewMpT", - "publicKey": "beee088bccea272eb6473fcc1cd3e22f2fc8d3a253a6398b69f5aab94070e690" - }, - "ocrKeyBundle": { - "bundleID": "9fba2d29874bb06b07272bd9141f096c1987d790bb0f81c3ffaf66d11cdac4f2", - "configPublicKey": "66dec87065de79e64ed4edd2478ec40a66f955af56e7b837729f464f8487d713", - "offchainPublicKey": "a0f59d50078c77812da8d3077f552209adfb58e76b635e008b6b0f872ce52139", - "onchainSigningAddress": "ed25406f1ef2e1381f6e1e04341f1a6e8b4eacea" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:26:37.622463Z" - }, - { - "id": "69", - "keys": [ - "keystone-07" - ], - "name": "Chainlink Keystone Node Operator 7", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "816", - "name": "Chainlink Sepolia Prod Keystone Cap One 7", - "publicKey": "50d4e3393516d1998e5c39874d7c0da2291e4e3727f8baac4380e9f5573cc648", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x0ba7c1096B701A862bBCe7F13E9D33eED7e33c1D", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQswQr8fxJG5ieMrayptGV4rvCjDWPCFtfkqm4L6NZbbb", - "publicKey": "dfc9a26dc022bd244c13d62ca88bbe62ca996065bd23224e1f1b77128914d84e" - }, - "ocrKeyBundle": { - "bundleID": "d4566a0c2f256e59733ad2a6dff9f388a1e00b2e65ec1cff7590cb59028888cd", - "configPublicKey": "58db0da621471e616615b8c1c1658ee3b7afbfa64662ce28b38272a95964052c", - "offchainPublicKey": "262fee9de8dd0c8758ba78de8873fdb6705c45ce331bc16ac81dc5b5f0b9680f", - "onchainSigningAddress": "516a9990d3a202b25c2cdd2f6316f4d066543e5d" - }, - "plugins": {} - } - }, - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0xcC44eD47023Bd88B82092A708c38609e8Fc2D197", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQswQr8fxJG5ieMrayptGV4rvCjDWPCFtfkqm4L6NZbbb", - "publicKey": "dfc9a26dc022bd244c13d62ca88bbe62ca996065bd23224e1f1b77128914d84e" - }, - "ocrKeyBundle": { - "bundleID": "d4566a0c2f256e59733ad2a6dff9f388a1e00b2e65ec1cff7590cb59028888cd", - "configPublicKey": "58db0da621471e616615b8c1c1658ee3b7afbfa64662ce28b38272a95964052c", - "offchainPublicKey": "262fee9de8dd0c8758ba78de8873fdb6705c45ce331bc16ac81dc5b5f0b9680f", - "onchainSigningAddress": "516a9990d3a202b25c2cdd2f6316f4d066543e5d" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0x0E8F4E699cd331022FaA2Ad75E500e70303C8767", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQswQr8fxJG5ieMrayptGV4rvCjDWPCFtfkqm4L6NZbbb", - "publicKey": "dfc9a26dc022bd244c13d62ca88bbe62ca996065bd23224e1f1b77128914d84e" - }, - "ocrKeyBundle": { - "bundleID": "d4566a0c2f256e59733ad2a6dff9f388a1e00b2e65ec1cff7590cb59028888cd", - "configPublicKey": "58db0da621471e616615b8c1c1658ee3b7afbfa64662ce28b38272a95964052c", - "offchainPublicKey": "262fee9de8dd0c8758ba78de8873fdb6705c45ce331bc16ac81dc5b5f0b9680f", - "onchainSigningAddress": "516a9990d3a202b25c2cdd2f6316f4d066543e5d" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x49c36b3BEc6b6e0e77305273FAFC68f479630535", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQswQr8fxJG5ieMrayptGV4rvCjDWPCFtfkqm4L6NZbbb", - "publicKey": "dfc9a26dc022bd244c13d62ca88bbe62ca996065bd23224e1f1b77128914d84e" - }, - "ocrKeyBundle": { - "bundleID": "d4566a0c2f256e59733ad2a6dff9f388a1e00b2e65ec1cff7590cb59028888cd", - "configPublicKey": "58db0da621471e616615b8c1c1658ee3b7afbfa64662ce28b38272a95964052c", - "offchainPublicKey": "262fee9de8dd0c8758ba78de8873fdb6705c45ce331bc16ac81dc5b5f0b9680f", - "onchainSigningAddress": "516a9990d3a202b25c2cdd2f6316f4d066543e5d" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:30:51.07624Z" - }, - { - "id": "70", - "keys": [ - "keystone-06" - ], - "name": "Chainlink Keystone Node Operator 6", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "815", - "name": "Chainlink Sepolia Prod Keystone Cap One 6", - "publicKey": "2669981add3071fae5dfd760fe97e7d2b90157f86b40227f306f1f3906099fc3", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x405eE4ad3E79786f899810ff6de16a83A920Db5D", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWHB1ucYgRqrocS6t834wL5XaB11JSPgKwzB6QwRPzRayu", - "publicKey": "6d4c18afa813bf7eec73e98a260294bce4b0b26eb9f6efceb2c9402eead56c98" - }, - "ocrKeyBundle": { - "bundleID": "d55283594d4e2c3e507f81ea9ad96261ebec1b1e8579bb1392ca22f7dc9b471b", - "configPublicKey": "32d5b6d38147fa23ec1dc4eeb240e2e70ea768b9a5182676075acd5a2ab2794c", - "offchainPublicKey": "9922cb5c0ae08f0b917979593824bde7ddad0935950e2835914acc34f6cd62f3", - "onchainSigningAddress": "bca900017893ea1366c110941d698d078c2b93ca" - }, - "plugins": {} - } - }, - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0x58D39d629ae9f904b0Ae509179b9e7c9B0184cee", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWHB1ucYgRqrocS6t834wL5XaB11JSPgKwzB6QwRPzRayu", - "publicKey": "6d4c18afa813bf7eec73e98a260294bce4b0b26eb9f6efceb2c9402eead56c98" - }, - "ocrKeyBundle": { - "bundleID": "d55283594d4e2c3e507f81ea9ad96261ebec1b1e8579bb1392ca22f7dc9b471b", - "configPublicKey": "32d5b6d38147fa23ec1dc4eeb240e2e70ea768b9a5182676075acd5a2ab2794c", - "offchainPublicKey": "9922cb5c0ae08f0b917979593824bde7ddad0935950e2835914acc34f6cd62f3", - "onchainSigningAddress": "bca900017893ea1366c110941d698d078c2b93ca" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0x34bFe10F4f4e1101b019639ABd5E5eE5186B80E6", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWHB1ucYgRqrocS6t834wL5XaB11JSPgKwzB6QwRPzRayu", - "publicKey": "6d4c18afa813bf7eec73e98a260294bce4b0b26eb9f6efceb2c9402eead56c98" - }, - "ocrKeyBundle": { - "bundleID": "d55283594d4e2c3e507f81ea9ad96261ebec1b1e8579bb1392ca22f7dc9b471b", - "configPublicKey": "32d5b6d38147fa23ec1dc4eeb240e2e70ea768b9a5182676075acd5a2ab2794c", - "offchainPublicKey": "9922cb5c0ae08f0b917979593824bde7ddad0935950e2835914acc34f6cd62f3", - "onchainSigningAddress": "bca900017893ea1366c110941d698d078c2b93ca" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x1741EB7468A490b4A9BA6f4CC7A47B82EcD65c4c", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWHB1ucYgRqrocS6t834wL5XaB11JSPgKwzB6QwRPzRayu", - "publicKey": "6d4c18afa813bf7eec73e98a260294bce4b0b26eb9f6efceb2c9402eead56c98" - }, - "ocrKeyBundle": { - "bundleID": "d55283594d4e2c3e507f81ea9ad96261ebec1b1e8579bb1392ca22f7dc9b471b", - "configPublicKey": "32d5b6d38147fa23ec1dc4eeb240e2e70ea768b9a5182676075acd5a2ab2794c", - "offchainPublicKey": "9922cb5c0ae08f0b917979593824bde7ddad0935950e2835914acc34f6cd62f3", - "onchainSigningAddress": "bca900017893ea1366c110941d698d078c2b93ca" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:32:14.024795Z" - }, - { - "id": "71", - "keys": [ - "keystone-05" - ], - "name": "Chainlink Keystone Node Operator 5", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "814", - "name": "Chainlink Sepolia Prod Keystone Cap One 5", - "publicKey": "94e9ee398547f1564b8b5f72c6148e511919ed0e59b94ae848d63685108f2ab4", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xbd1ee3165178D3A3E38458a9Fb1d6BF7fb5C443e", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCiwWc97Q3Z9YUGZcAf46TMLg1uMvrEDa4gT6HZUFFCB1", - "publicKey": "2b2f46bf3b7ab2f39a7fec18166a6ebbc0a72209e920c33933f9adf07b101cc0" - }, - "ocrKeyBundle": { - "bundleID": "bf1736a09452daa0923f2c680f3fa6362ae652294e80ce72d923b304b0dcbb13", - "configPublicKey": "4ebd2a563c458485d2698d06142daa37ea2bee706b4a1a71c8435f2ec254506a", - "offchainPublicKey": "8577b96b270b36e74eb5d411caa14353cdadea599d6d6aa9cccf534ce31f1ef5", - "onchainSigningAddress": "b6727a31772b71d15e3120bfd618545292e1f9df" - }, - "plugins": {} - } - }, - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0x9b6284B5775E46fB02C1a589596EF07c35b55377", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCiwWc97Q3Z9YUGZcAf46TMLg1uMvrEDa4gT6HZUFFCB1", - "publicKey": "2b2f46bf3b7ab2f39a7fec18166a6ebbc0a72209e920c33933f9adf07b101cc0" - }, - "ocrKeyBundle": { - "bundleID": "bf1736a09452daa0923f2c680f3fa6362ae652294e80ce72d923b304b0dcbb13", - "configPublicKey": "4ebd2a563c458485d2698d06142daa37ea2bee706b4a1a71c8435f2ec254506a", - "offchainPublicKey": "8577b96b270b36e74eb5d411caa14353cdadea599d6d6aa9cccf534ce31f1ef5", - "onchainSigningAddress": "b6727a31772b71d15e3120bfd618545292e1f9df" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0xD83DCED517E4df64e913B97b3d0A906e4CA63d43", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCiwWc97Q3Z9YUGZcAf46TMLg1uMvrEDa4gT6HZUFFCB1", - "publicKey": "2b2f46bf3b7ab2f39a7fec18166a6ebbc0a72209e920c33933f9adf07b101cc0" - }, - "ocrKeyBundle": { - "bundleID": "bf1736a09452daa0923f2c680f3fa6362ae652294e80ce72d923b304b0dcbb13", - "configPublicKey": "4ebd2a563c458485d2698d06142daa37ea2bee706b4a1a71c8435f2ec254506a", - "offchainPublicKey": "8577b96b270b36e74eb5d411caa14353cdadea599d6d6aa9cccf534ce31f1ef5", - "onchainSigningAddress": "b6727a31772b71d15e3120bfd618545292e1f9df" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xFF1218066b4b5Cd9dE2A73639862082bcC98bf0D", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCiwWc97Q3Z9YUGZcAf46TMLg1uMvrEDa4gT6HZUFFCB1", - "publicKey": "2b2f46bf3b7ab2f39a7fec18166a6ebbc0a72209e920c33933f9adf07b101cc0" - }, - "ocrKeyBundle": { - "bundleID": "bf1736a09452daa0923f2c680f3fa6362ae652294e80ce72d923b304b0dcbb13", - "configPublicKey": "4ebd2a563c458485d2698d06142daa37ea2bee706b4a1a71c8435f2ec254506a", - "offchainPublicKey": "8577b96b270b36e74eb5d411caa14353cdadea599d6d6aa9cccf534ce31f1ef5", - "onchainSigningAddress": "b6727a31772b71d15e3120bfd618545292e1f9df" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:38:35.588611Z" - }, - { - "id": "72", - "keys": [ - "keystone-04" - ], - "name": "Chainlink Keystone Node Operator 4", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "813", - "name": "Chainlink Sepolia Prod Keystone Cap One 4", - "publicKey": "a618fe2d3260151957d105d2dd593dddaad20c45dc6ae8eab265504e6585a02c", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xE73E4D047DA32De40C7008075aEb9F60C8AF3C90", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWPMfQRpMy3wYzSMe3BLS8GFuC3fauk7FhTtgfbtp6T6jT", - "publicKey": "c92c6c81f3dff17c05577b9f87177d735d797a3ceedc0fa1395682dfbb66a8d2" - }, - "ocrKeyBundle": { - "bundleID": "fbcfd8420c2ebc450c81fcf72c6673fdd786702c881467e69817c20350bf819b", - "configPublicKey": "282a47a24fd976134f25a99f6370e072f228098010d2594d849d0a4c2788f878", - "offchainPublicKey": "1a7902a01e27818cda034637fdce603a265bc380934324b6f48cf23873234ec6", - "onchainSigningAddress": "7e799378dda3dcdc503233735f09150f0684be19" - }, - "plugins": {} - } - }, - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0x7501ff3462fd2133f2E1F93DB7Ec514988B43E56", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWPMfQRpMy3wYzSMe3BLS8GFuC3fauk7FhTtgfbtp6T6jT", - "publicKey": "c92c6c81f3dff17c05577b9f87177d735d797a3ceedc0fa1395682dfbb66a8d2" - }, - "ocrKeyBundle": { - "bundleID": "fbcfd8420c2ebc450c81fcf72c6673fdd786702c881467e69817c20350bf819b", - "configPublicKey": "282a47a24fd976134f25a99f6370e072f228098010d2594d849d0a4c2788f878", - "offchainPublicKey": "1a7902a01e27818cda034637fdce603a265bc380934324b6f48cf23873234ec6", - "onchainSigningAddress": "7e799378dda3dcdc503233735f09150f0684be19" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0xef080765890a3F697C4920609621fe301Dd34A70", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWPMfQRpMy3wYzSMe3BLS8GFuC3fauk7FhTtgfbtp6T6jT", - "publicKey": "c92c6c81f3dff17c05577b9f87177d735d797a3ceedc0fa1395682dfbb66a8d2" - }, - "ocrKeyBundle": { - "bundleID": "fbcfd8420c2ebc450c81fcf72c6673fdd786702c881467e69817c20350bf819b", - "configPublicKey": "282a47a24fd976134f25a99f6370e072f228098010d2594d849d0a4c2788f878", - "offchainPublicKey": "1a7902a01e27818cda034637fdce603a265bc380934324b6f48cf23873234ec6", - "onchainSigningAddress": "7e799378dda3dcdc503233735f09150f0684be19" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x860235D5Db42eF568665900BBD6bA3DB2fA4f33f", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWPMfQRpMy3wYzSMe3BLS8GFuC3fauk7FhTtgfbtp6T6jT", - "publicKey": "c92c6c81f3dff17c05577b9f87177d735d797a3ceedc0fa1395682dfbb66a8d2" - }, - "ocrKeyBundle": { - "bundleID": "fbcfd8420c2ebc450c81fcf72c6673fdd786702c881467e69817c20350bf819b", - "configPublicKey": "282a47a24fd976134f25a99f6370e072f228098010d2594d849d0a4c2788f878", - "offchainPublicKey": "1a7902a01e27818cda034637fdce603a265bc380934324b6f48cf23873234ec6", - "onchainSigningAddress": "7e799378dda3dcdc503233735f09150f0684be19" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:39:26.24249Z" - }, - { - "id": "73", - "keys": [ - "keystone-03", - "keystone-bt-03" - ], - "name": "Chainlink Keystone Node Operator 3", - "metadata": { - "nodeCount": 3, - "jobCount": 5 - }, - "nodes": [ - { - "id": "812", - "name": "Chainlink Sepolia Prod Keystone Cap One 3", - "publicKey": "f4cf97438c3ad86003e5c0368ab52c70f7fbb7f39ae0d7bf6dacbe16807e8a36", - "chainConfigs": [ - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0x646665317aF70313B3E83Ea1369A91de389DaCAe", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWAvLkcnc8Zttykk6gGeTWFiT6TqgovRHnb6Ym6QqjnLVM", - "publicKey": "1063921b717c3e32210d2803fe684cd818ea2a4a96e405373e5786c8a13c7600" - }, - "ocrKeyBundle": { - "bundleID": "5b46ab201ba66bd93bae6f41afc59c2e578e0f5682fbdf76e1b647fde6d6e8dd", - "configPublicKey": "a01d7d13f3e67ff84ff208cc44c923fe245d02d6029c91dc38422ef44f2bb26e", - "offchainPublicKey": "64eded06a47efc5e311799c1e1fa833cf78d17f079b2f6019c3247debe490439", - "onchainSigningAddress": "afca74e3b850a9435b2dc479ca8bc8e1b45dd0b2" - }, - "plugins": {} - } - }, - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0x3Ab2A4e4765A0374F727a9a9eCE893734e2928ec", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWAvLkcnc8Zttykk6gGeTWFiT6TqgovRHnb6Ym6QqjnLVM", - "publicKey": "1063921b717c3e32210d2803fe684cd818ea2a4a96e405373e5786c8a13c7600" - }, - "ocrKeyBundle": { - "bundleID": "5b46ab201ba66bd93bae6f41afc59c2e578e0f5682fbdf76e1b647fde6d6e8dd", - "configPublicKey": "a01d7d13f3e67ff84ff208cc44c923fe245d02d6029c91dc38422ef44f2bb26e", - "offchainPublicKey": "64eded06a47efc5e311799c1e1fa833cf78d17f079b2f6019c3247debe490439", - "onchainSigningAddress": "afca74e3b850a9435b2dc479ca8bc8e1b45dd0b2" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x9905E8C3A4f82037170a8c411CD8b11D4894066f", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWAvLkcnc8Zttykk6gGeTWFiT6TqgovRHnb6Ym6QqjnLVM", - "publicKey": "1063921b717c3e32210d2803fe684cd818ea2a4a96e405373e5786c8a13c7600" - }, - "ocrKeyBundle": { - "bundleID": "5b46ab201ba66bd93bae6f41afc59c2e578e0f5682fbdf76e1b647fde6d6e8dd", - "configPublicKey": "a01d7d13f3e67ff84ff208cc44c923fe245d02d6029c91dc38422ef44f2bb26e", - "offchainPublicKey": "64eded06a47efc5e311799c1e1fa833cf78d17f079b2f6019c3247debe490439", - "onchainSigningAddress": "afca74e3b850a9435b2dc479ca8bc8e1b45dd0b2" - }, - "plugins": {} - } - }, - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x762354eC86ea2253F5da27FF8b952Cb7Dec52B6D", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWAvLkcnc8Zttykk6gGeTWFiT6TqgovRHnb6Ym6QqjnLVM", - "publicKey": "1063921b717c3e32210d2803fe684cd818ea2a4a96e405373e5786c8a13c7600" - }, - "ocrKeyBundle": { - "bundleID": "5b46ab201ba66bd93bae6f41afc59c2e578e0f5682fbdf76e1b647fde6d6e8dd", - "configPublicKey": "a01d7d13f3e67ff84ff208cc44c923fe245d02d6029c91dc38422ef44f2bb26e", - "offchainPublicKey": "64eded06a47efc5e311799c1e1fa833cf78d17f079b2f6019c3247debe490439", - "onchainSigningAddress": "afca74e3b850a9435b2dc479ca8bc8e1b45dd0b2" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:40:30.499914Z" - }, - { - "id": "74", - "keys": [ - "keystone-02", - "keystone-bt-02" - ], - "name": "Chainlink Keystone Node Operator 2", - "metadata": { - "nodeCount": 3, - "jobCount": 5 - }, - "nodes": [ - { - "id": "811", - "name": "Chainlink Sepolia Prod Keystone Cap One 2", - "publicKey": "a1f112923513f13ede1ca8f982ea0ab6221d584b40cd57f0c82307ab79c0e69f", - "chainConfigs": [ - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0xbF1Ad47D99A65e230235537b47C8D1Dddb22FD53", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQhLYuAxx4WDKafnuhZUTix8Y24gtB92vEUpAC4EdH4VA", - "publicKey": "dd1268a3e7ed4b9c83b1227e5bf2558e6b77af585c66e88a06f1164a1a94f8ed" - }, - "ocrKeyBundle": { - "bundleID": "a11d9438035564bfe84fcfb513b579edbe173fa26c00331e71a010d00b856037", - "configPublicKey": "407cab2a04fa868f645c6848a53abdb8136b08441c50b191651c4f1a348ee700", - "offchainPublicKey": "64a3215839e5630f12ae66b4363f40d82e9c981118c304ca0c4ca5fc2c6e1f37", - "onchainSigningAddress": "6579d77791ee8f8116495dbe6fa6586980177230" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0xa8d4698f74a0A427c1b8ec4575d9dFdD17Be288c", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQhLYuAxx4WDKafnuhZUTix8Y24gtB92vEUpAC4EdH4VA", - "publicKey": "dd1268a3e7ed4b9c83b1227e5bf2558e6b77af585c66e88a06f1164a1a94f8ed" - }, - "ocrKeyBundle": { - "bundleID": "a11d9438035564bfe84fcfb513b579edbe173fa26c00331e71a010d00b856037", - "configPublicKey": "407cab2a04fa868f645c6848a53abdb8136b08441c50b191651c4f1a348ee700", - "offchainPublicKey": "64a3215839e5630f12ae66b4363f40d82e9c981118c304ca0c4ca5fc2c6e1f37", - "onchainSigningAddress": "6579d77791ee8f8116495dbe6fa6586980177230" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xf286c79b4a613a1fE480C8e4fB17B837E7D8ba03", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQhLYuAxx4WDKafnuhZUTix8Y24gtB92vEUpAC4EdH4VA", - "publicKey": "dd1268a3e7ed4b9c83b1227e5bf2558e6b77af585c66e88a06f1164a1a94f8ed" - }, - "ocrKeyBundle": { - "bundleID": "a11d9438035564bfe84fcfb513b579edbe173fa26c00331e71a010d00b856037", - "configPublicKey": "407cab2a04fa868f645c6848a53abdb8136b08441c50b191651c4f1a348ee700", - "offchainPublicKey": "64a3215839e5630f12ae66b4363f40d82e9c981118c304ca0c4ca5fc2c6e1f37", - "onchainSigningAddress": "6579d77791ee8f8116495dbe6fa6586980177230" - }, - "plugins": {} - } - }, - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xfe85A25cE2CB58b280CC0316305fC678Bf570f5e", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQhLYuAxx4WDKafnuhZUTix8Y24gtB92vEUpAC4EdH4VA", - "publicKey": "dd1268a3e7ed4b9c83b1227e5bf2558e6b77af585c66e88a06f1164a1a94f8ed" - }, - "ocrKeyBundle": { - "bundleID": "a11d9438035564bfe84fcfb513b579edbe173fa26c00331e71a010d00b856037", - "configPublicKey": "407cab2a04fa868f645c6848a53abdb8136b08441c50b191651c4f1a348ee700", - "offchainPublicKey": "64a3215839e5630f12ae66b4363f40d82e9c981118c304ca0c4ca5fc2c6e1f37", - "onchainSigningAddress": "6579d77791ee8f8116495dbe6fa6586980177230" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:41:33.205484Z" - }, - { - "id": "75", - "keys": [ - "keystone-01", - "keystone-bt-01" - ], - "name": "Chainlink Keystone Node Operator 1", - "metadata": { - "nodeCount": 3, - "jobCount": 5 - }, - "nodes": [ - { - "id": "810", - "name": "Chainlink Sepolia Prod Keystone Cap One 1", - "publicKey": "9ef27cd1855a0ed6932be33c80d7cd9c178307e5a240dbeb9055946359dc5d7f", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xBB465BCa1b289269F2a95a36f5B6fD006Af56ede", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMNg1a7HvNWuHAPMdveWr1J6NNCVBU1Z4w5swzepT5Wvf", - "publicKey": "abb750e04bee21d830c6ce0f08180853466139fc6055c6737614797c0704d59c" - }, - "ocrKeyBundle": { - "bundleID": "0d176a4c2d68c619d237e419c31a030e5b2162ee031baa8ebc8472623da9b067", - "configPublicKey": "43e4dbf80a9c818a7d35c080f61b6f8f9b175fa1217b1d01168140da75322d5c", - "offchainPublicKey": "707db88237aaaaddc22bf0fe914540ea7b8bbfbe5cf88349cabb26e34762237c", - "onchainSigningAddress": "ac08f52ec257ddbb493e7b9e299dd2c166a7f090" - }, - "plugins": {} - } - }, - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0x5e3618cFF8Ab337b3c73c2775d1a2EC65e5abEF0", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMNg1a7HvNWuHAPMdveWr1J6NNCVBU1Z4w5swzepT5Wvf", - "publicKey": "abb750e04bee21d830c6ce0f08180853466139fc6055c6737614797c0704d59c" - }, - "ocrKeyBundle": { - "bundleID": "0d176a4c2d68c619d237e419c31a030e5b2162ee031baa8ebc8472623da9b067", - "configPublicKey": "43e4dbf80a9c818a7d35c080f61b6f8f9b175fa1217b1d01168140da75322d5c", - "offchainPublicKey": "707db88237aaaaddc22bf0fe914540ea7b8bbfbe5cf88349cabb26e34762237c", - "onchainSigningAddress": "ac08f52ec257ddbb493e7b9e299dd2c166a7f090" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0x1796BbC2AbbAd5660C8a7812b313E1f48A99f1D1", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMNg1a7HvNWuHAPMdveWr1J6NNCVBU1Z4w5swzepT5Wvf", - "publicKey": "abb750e04bee21d830c6ce0f08180853466139fc6055c6737614797c0704d59c" - }, - "ocrKeyBundle": { - "bundleID": "0d176a4c2d68c619d237e419c31a030e5b2162ee031baa8ebc8472623da9b067", - "configPublicKey": "43e4dbf80a9c818a7d35c080f61b6f8f9b175fa1217b1d01168140da75322d5c", - "offchainPublicKey": "707db88237aaaaddc22bf0fe914540ea7b8bbfbe5cf88349cabb26e34762237c", - "onchainSigningAddress": "ac08f52ec257ddbb493e7b9e299dd2c166a7f090" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xA2bfAc45e6878fbE04525C23dFbb11fFb224Ea60", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMNg1a7HvNWuHAPMdveWr1J6NNCVBU1Z4w5swzepT5Wvf", - "publicKey": "abb750e04bee21d830c6ce0f08180853466139fc6055c6737614797c0704d59c" - }, - "ocrKeyBundle": { - "bundleID": "0d176a4c2d68c619d237e419c31a030e5b2162ee031baa8ebc8472623da9b067", - "configPublicKey": "43e4dbf80a9c818a7d35c080f61b6f8f9b175fa1217b1d01168140da75322d5c", - "offchainPublicKey": "707db88237aaaaddc22bf0fe914540ea7b8bbfbe5cf88349cabb26e34762237c", - "onchainSigningAddress": "ac08f52ec257ddbb493e7b9e299dd2c166a7f090" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:42:05.709664Z" - }, - { - "id": "76", - "keys": [ - "keystone-00", - "keystone-bt-00" - ], - "name": "Chainlink Keystone Node Operator 0", - "metadata": { - "nodeCount": 3, - "jobCount": 5 - }, - "nodes": [ - { - "id": "809", - "name": "Chainlink Sepolia Prod Keystone Cap One 0", - "publicKey": "545197637db59b96b22528ff90960b9e7cdcea81c8a5a9f06ae6b728bcba35cb", - "chainConfigs": [ - { - "network": { - "id": "10", - "chainID": "43113", - "chainType": "EVM", - "name": "Avalanche Testnet (Fuji)" - }, - "accountAddress": "0x66a88b0a23D8351e8F5e228eEe8439e65F423842", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWFux8Vvs8CPfUSKitXwQsq81ZBhQYcbKRH5L5jkFbQ6nH", - "publicKey": "5a946cfec8e3c33f6c88961dcab2bbd8bb9d05538c8f931bb62d59b1d7fd782e" - }, - "ocrKeyBundle": { - "bundleID": "d9a3c3afdb310ba11b058afd6ee3159edfbc740df4daefd65c257a7ed46ed9ef", - "configPublicKey": "64fd95e7bcbb33e3dd548247352bb7be5ea6577a840e5e3b66336f710b5b272e", - "offchainPublicKey": "216b1e3dc51ad21be806c010397cc2e0bf59b2a06ade89bc7d0c0a7299a4e01e", - "onchainSigningAddress": "a4f0acbe902443aa842db278f421da99cdc47a8b" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x36a46774A3743641D4C274b385608Cb455B5B6b8", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWFux8Vvs8CPfUSKitXwQsq81ZBhQYcbKRH5L5jkFbQ6nH", - "publicKey": "5a946cfec8e3c33f6c88961dcab2bbd8bb9d05538c8f931bb62d59b1d7fd782e" - }, - "ocrKeyBundle": { - "bundleID": "d9a3c3afdb310ba11b058afd6ee3159edfbc740df4daefd65c257a7ed46ed9ef", - "configPublicKey": "64fd95e7bcbb33e3dd548247352bb7be5ea6577a840e5e3b66336f710b5b272e", - "offchainPublicKey": "216b1e3dc51ad21be806c010397cc2e0bf59b2a06ade89bc7d0c0a7299a4e01e", - "onchainSigningAddress": "a4f0acbe902443aa842db278f421da99cdc47a8b" - }, - "plugins": {} - } - }, - { - "network": { - "id": "147", - "chainID": "84532", - "chainType": "EVM", - "name": "Base Testnet (Sepolia)" - }, - "accountAddress": "0x868ab67c00fF7e21aFf470C066798e5bE4240305", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWFux8Vvs8CPfUSKitXwQsq81ZBhQYcbKRH5L5jkFbQ6nH", - "publicKey": "5a946cfec8e3c33f6c88961dcab2bbd8bb9d05538c8f931bb62d59b1d7fd782e" - }, - "ocrKeyBundle": { - "bundleID": "d9a3c3afdb310ba11b058afd6ee3159edfbc740df4daefd65c257a7ed46ed9ef", - "configPublicKey": "64fd95e7bcbb33e3dd548247352bb7be5ea6577a840e5e3b66336f710b5b272e", - "offchainPublicKey": "216b1e3dc51ad21be806c010397cc2e0bf59b2a06ade89bc7d0c0a7299a4e01e", - "onchainSigningAddress": "a4f0acbe902443aa842db278f421da99cdc47a8b" - }, - "plugins": {} - } - }, - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xa60bC482fCfcd12B752541a00555E4e448Bc1d16", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWFux8Vvs8CPfUSKitXwQsq81ZBhQYcbKRH5L5jkFbQ6nH", - "publicKey": "5a946cfec8e3c33f6c88961dcab2bbd8bb9d05538c8f931bb62d59b1d7fd782e" - }, - "ocrKeyBundle": { - "bundleID": "d9a3c3afdb310ba11b058afd6ee3159edfbc740df4daefd65c257a7ed46ed9ef", - "configPublicKey": "64fd95e7bcbb33e3dd548247352bb7be5ea6577a840e5e3b66336f710b5b272e", - "offchainPublicKey": "216b1e3dc51ad21be806c010397cc2e0bf59b2a06ade89bc7d0c0a7299a4e01e", - "onchainSigningAddress": "a4f0acbe902443aa842db278f421da99cdc47a8b" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "OCR3_CAPABILITY", - "DATA_STREAMS_V03" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:42:49.446864Z" - } -] diff --git a/deployment/keystone/testdata/ocr3config.json b/deployment/keystone/testdata/ocr3config.json deleted file mode 100644 index 6835a4143f4..00000000000 --- a/deployment/keystone/testdata/ocr3config.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "OracleConfig": { - "MaxQueryLengthBytes": 1000000, - "MaxObservationLengthBytes": 1000000, - "MaxReportLengthBytes": 1000000, - "MaxRequestBatchSize": 1000, - "UniqueReports": true, - - "DeltaProgressMillis": 5000, - "DeltaResendMillis": 5000, - "DeltaInitialMillis": 5000, - "DeltaRoundMillis": 2000, - "DeltaGraceMillis": 500, - "DeltaCertifiedCommitRequestMillis": 1000, - "DeltaStageMillis": 30000, - "MaxRoundsPerEpoch": 10, - "TransmissionSchedule": [1, 1, 1, 1], - - "MaxDurationQueryMillis": 1000, - "MaxDurationObservationMillis": 1000, - "MaxDurationReportMillis": 1000, - "MaxDurationAcceptMillis": 1000, - "MaxDurationTransmitMillis": 1000, - - "MaxFaultyOracles": 1 - } -} diff --git a/deployment/keystone/testdata/workflow_nodes.json b/deployment/keystone/testdata/workflow_nodes.json deleted file mode 100644 index a5cf7de56fd..00000000000 --- a/deployment/keystone/testdata/workflow_nodes.json +++ /dev/null @@ -1,1107 +0,0 @@ - -[ - { - "id": "67", - "keys": [ - "keystone-09" - ], - "name": "Chainlink Keystone Node Operator 9", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "780", - "name": "Chainlink Sepolia Prod Keystone One 9", - "publicKey": "412dc6fe48ea4e34baaa77da2e3b032d39b938597b6f3d61fe7ed183a827a431", - "chainConfigs": [ - { - "network": { - "id": "1401", - "chainID": "2", - "chainType": "APTOS", - "name": "APTOS TEST" - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE8TxNr5dM4U", - "publicKey": "147d5cc651819b093cd2fdff9760f0f0f77b7ef7798d9e24fc6a350b7300e5d9" - }, - "ocrKeyBundle": { - "bundleID": "d834cf7c830df7510228b33b138c018ff16b4eecf82273ed3bcd862bbbc046d4", - "configPublicKey": "6a1f37f06833c55ecf46233439ea6179a835bac6f2b2dee725b747c121813149", - "offchainPublicKey": "ff1144bbf648e6f76c58d0ce53a9a2cbe9a284d52db8691a714cac8e3a96b8b4", - "onchainSigningAddress": "4fa557850e4d5c21b3963c97414c1f37792700c4d3b8abdb904b765fd47e39bf" - }, - "plugins": {} - } - }, - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xbA8E21dFaa0501fCD43146d0b5F21c2B8E0eEdfB", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE8TxNr5dM4U", - "publicKey": "147d5cc651819b093cd2fdff9760f0f0f77b7ef7798d9e24fc6a350b7300e5d9" - }, - "ocrKeyBundle": { - "bundleID": "1c28e76d180d1ed1524e61845fa58a384415de7e51017edf1f8c553e28357772", - "configPublicKey": "09fced0207611ed618bf0759ab128d9797e15b18e46436be1a56a91e4043ec0e", - "offchainPublicKey": "c805572b813a072067eab2087ddbee8aa719090e12890b15c01094f0d3f74a5f", - "onchainSigningAddress": "679296b7c1eb4948efcc87efc550940a182e610c" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x0b04cE574E80Da73191Ec141c0016a54A6404056", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWBCMCCZZ8x57AXvJvpCujqhZzTjWXbReaRE8TxNr5dM4U", - "publicKey": "147d5cc651819b093cd2fdff9760f0f0f77b7ef7798d9e24fc6a350b7300e5d9" - }, - "ocrKeyBundle": { - "bundleID": "1c28e76d180d1ed1524e61845fa58a384415de7e51017edf1f8c553e28357772", - "configPublicKey": "09fced0207611ed618bf0759ab128d9797e15b18e46436be1a56a91e4043ec0e", - "offchainPublicKey": "c805572b813a072067eab2087ddbee8aa719090e12890b15c01094f0d3f74a5f", - "onchainSigningAddress": "679296b7c1eb4948efcc87efc550940a182e610c" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T19:00:07.113658Z" - }, - { - "id": "68", - "keys": [ - "keystone-08" - ], - "name": "Chainlink Keystone Node Operator 8", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "781", - "name": "Chainlink Sepolia Prod Keystone One 8", - "publicKey": "1141dd1e46797ced9b0fbad49115f18507f6f6e6e3cc86e7e5ba169e58645adc", - "chainConfigs": [ - { - "network": { - "id": "1402", - "chainID": "2", - "chainType": "APTOS", - "name": "APTOS TEST" - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWAUagqMycsro27kFznSQRHbhfCBLx8nKD4ptTiUGDe38c", - "publicKey": "09ca39cd924653c72fbb0e458b629c3efebdad3e29e7cd0b5760754d919ed829" - }, - "ocrKeyBundle": { - "bundleID": "6726df46033038b724a4e6371807b6aa09efc829d0a3f7a5db4fd7df4b69fea7", - "configPublicKey": "0874e6cd5c8e651ab0ff564a474832ed9eaf2c5025b553f908d04921d9777d50", - "offchainPublicKey": "c791d2b9d3562f991af68ab7164a19734d551a9404d91c9571fdcdc5dcb237ca", - "onchainSigningAddress": "bddafb20cc50d89e0ae2f244908c27b1d639615d8186b28c357669de3359f208" - }, - "plugins": {} - } - }, - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xEa4bC3638660D78Da56f39f6680dCDD0cEAaD2c6", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWAUagqMycsro27kFznSQRHbhfCBLx8nKD4ptTiUGDe38c", - "publicKey": "09ca39cd924653c72fbb0e458b629c3efebdad3e29e7cd0b5760754d919ed829" - }, - "ocrKeyBundle": { - "bundleID": "be0d639de3ae3cbeaa31ca369514f748ba1d271145cba6796bcc12aace2f64c3", - "configPublicKey": "e3d4d7a7372a3b1110db0290ab3649eb5fbb0daf6cf3ae02cfe5f367700d9264", - "offchainPublicKey": "ad08c2a5878cada53521f4e2bb449f191ccca7899246721a0deeea19f7b83f70", - "onchainSigningAddress": "8c2aa1e6fad88a6006dfb116eb866cbad2910314" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x31B179dcF8f9036C30f04bE578793e51bF14A39E", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWAUagqMycsro27kFznSQRHbhfCBLx8nKD4ptTiUGDe38c", - "publicKey": "09ca39cd924653c72fbb0e458b629c3efebdad3e29e7cd0b5760754d919ed829" - }, - "ocrKeyBundle": { - "bundleID": "be0d639de3ae3cbeaa31ca369514f748ba1d271145cba6796bcc12aace2f64c3", - "configPublicKey": "e3d4d7a7372a3b1110db0290ab3649eb5fbb0daf6cf3ae02cfe5f367700d9264", - "offchainPublicKey": "ad08c2a5878cada53521f4e2bb449f191ccca7899246721a0deeea19f7b83f70", - "onchainSigningAddress": "8c2aa1e6fad88a6006dfb116eb866cbad2910314" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:26:37.622463Z" - }, - { - "id": "69", - "keys": [ - "keystone-07" - ], - "name": "Chainlink Keystone Node Operator 7", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "782", - "name": "Chainlink Sepolia Prod Keystone One 7", - "publicKey": "b473091fe1d4dbbc26ad71c67b4432f8f4280e06bab5e2122a92f4ab8b6ff2f5", - "chainConfigs": [ - { - "network": { - "id": "1403", - "chainID": "2", - "chainType": "APTOS", - "name": "APTOS TEST" - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQMCj73V5xmCd6C5VsJr7rbFG2TF9LwVcLiiBqXps9MgC", - "publicKey": "d7e9f2252b09edf0802a65b60bc9956691747894cb3ab9fefd072adf742eb9f1" - }, - "ocrKeyBundle": { - "bundleID": "14082da0f33b4cec842bc1e1002e617a194ed4a81105603bd6c1edf784aa3743", - "configPublicKey": "209eea27e73b0ecc1c49b3ea274e4a18a1f5ed62fd79f443f0b5b9cc6019356e", - "offchainPublicKey": "cf0684a0e59399fe9b92cfc740d9696f925e78ee7d0273947e5f7b830070eaaa", - "onchainSigningAddress": "96dc85670c49caa986de4ad288e680e9afb0f5491160dcbb4868ca718e194fc8" - }, - "plugins": {} - } - }, - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x65bE4739E187a39b859766C143b569acd5BE234d", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQMCj73V5xmCd6C5VsJr7rbFG2TF9LwVcLiiBqXps9MgC", - "publicKey": "d7e9f2252b09edf0802a65b60bc9956691747894cb3ab9fefd072adf742eb9f1" - }, - "ocrKeyBundle": { - "bundleID": "e6d6ffec6cff01ac20d57bc42626c8e955293f232d383bf468351d867a7b8213", - "configPublicKey": "4d2f75f98b911c20fe7808384312d8b913e6b7a98c34d05c6e461434c92b4502", - "offchainPublicKey": "01496edce35663071d74472e02119432ba059b3904d205e4358014410e4f2be3", - "onchainSigningAddress": "213803bb9f9715379aaf11aadb0212369701dc0a" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x9ad9f3AD49e5aB0F28bD694d211a90297bD90D7f", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWQMCj73V5xmCd6C5VsJr7rbFG2TF9LwVcLiiBqXps9MgC", - "publicKey": "d7e9f2252b09edf0802a65b60bc9956691747894cb3ab9fefd072adf742eb9f1" - }, - "ocrKeyBundle": { - "bundleID": "e6d6ffec6cff01ac20d57bc42626c8e955293f232d383bf468351d867a7b8213", - "configPublicKey": "4d2f75f98b911c20fe7808384312d8b913e6b7a98c34d05c6e461434c92b4502", - "offchainPublicKey": "01496edce35663071d74472e02119432ba059b3904d205e4358014410e4f2be3", - "onchainSigningAddress": "213803bb9f9715379aaf11aadb0212369701dc0a" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:30:51.07624Z" - }, - { - "id": "70", - "keys": [ - "keystone-06" - ], - "name": "Chainlink Keystone Node Operator 6", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "783", - "name": "Chainlink Sepolia Prod Keystone One 6", - "publicKey": "75ac63fc97a31e31168084e0de8ccd2bea90059b609d962f3e43fc296cdba28d", - "chainConfigs": [ - { - "network": { - "id": "1404", - "chainID": "2", - "chainType": "APTOS", - "name": "APTOS TEST" - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWNJ8de3PUURZ2oucrVTpnRTqNBTUYwHLQjK9LzN3E6Mfn", - "publicKey": "b96933429b1a81c811e1195389d7733e936b03e8086e75ea1fa92c61564b6c31" - }, - "ocrKeyBundle": { - "bundleID": "b419e9e3f1256aa2907a1a396bdf27ba5002a30eee440ab96cb60369429ce277", - "configPublicKey": "3ae1a1c713e4ad63f67191fd93620c9eebe44e1d5f3264036ec0fbcd59cf9664", - "offchainPublicKey": "6fc8c3fb55b39577abbab20028bee93d1d6d8a888dd298354b95d4af3ccb6009", - "onchainSigningAddress": "4a94c75cb9fe8b1fba86fd4b71ad130943281fdefad10216c46eb2285d60950f" - }, - "plugins": {} - } - }, - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x8706E716fc1ee972F3E4D42D42711Aa175Aa654A", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWNJ8de3PUURZ2oucrVTpnRTqNBTUYwHLQjK9LzN3E6Mfn", - "publicKey": "b96933429b1a81c811e1195389d7733e936b03e8086e75ea1fa92c61564b6c31" - }, - "ocrKeyBundle": { - "bundleID": "62d36269d916b4834b17dc6d637c1c39b0895396249a0845764c898e83f63525", - "configPublicKey": "8c6c7d889ac6cc9e663ae48073bbf130fae105d6a3689636db27752e3e3e6816", - "offchainPublicKey": "aa3419628ea3536783742d17d8adf05681aa6a6bd2b206fbde78c7e5aa38586d", - "onchainSigningAddress": "4885973b2fcf061d5cdfb8f74c5139bd3056e9da" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x19e10B063a62B1574AE19020A64fDe6419892dA6", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWNJ8de3PUURZ2oucrVTpnRTqNBTUYwHLQjK9LzN3E6Mfn", - "publicKey": "b96933429b1a81c811e1195389d7733e936b03e8086e75ea1fa92c61564b6c31" - }, - "ocrKeyBundle": { - "bundleID": "62d36269d916b4834b17dc6d637c1c39b0895396249a0845764c898e83f63525", - "configPublicKey": "8c6c7d889ac6cc9e663ae48073bbf130fae105d6a3689636db27752e3e3e6816", - "offchainPublicKey": "aa3419628ea3536783742d17d8adf05681aa6a6bd2b206fbde78c7e5aa38586d", - "onchainSigningAddress": "4885973b2fcf061d5cdfb8f74c5139bd3056e9da" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:32:14.024795Z" - }, - { - "id": "71", - "keys": [ - "keystone-05" - ], - "name": "Chainlink Keystone Node Operator 5", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "784", - "name": "Chainlink Sepolia Prod Keystone One 5", - "publicKey": "4542f4fd2ed150c8c976b39802fe3d994aec3ac94fd11e7817f693b1c9a1dabb", - "chainConfigs": [ - { - "network": { - "id": "14005", - "chainID": "2", - "chainType": "APTOS", - "name": "APTOS TEST" - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWR8d5kbZb7YiQWKpT1J1PfMqNaGAmb4jBFx9DWag4hpSZ", - "publicKey": "e38c9f2760db006f070e9cc1bc1c2269ad033751adaa85d022fb760cbc5b5ef6" - }, - "ocrKeyBundle": { - "bundleID": "44b5f46bfbb04d0984469298ec43c350ec6b2cd4556b18265ebac1b6cc329c7c", - "configPublicKey": "263bee0d09d90e0e618c4cdd630d1437f7377f2d544df57f39ddd47984970555", - "offchainPublicKey": "11674b98849d8e070ac69d37c284b3091fcd374913f52b2b83ce2d9a4a4e0213", - "onchainSigningAddress": "425d1354a7b8180252a221040c718cac0ba0251c7efe31a2acefbba578dc2153" - }, - "plugins": {} - } - }, - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xcea9f5C042130dD35Eff5B5a6E2361A0276570e3", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWR8d5kbZb7YiQWKpT1J1PfMqNaGAmb4jBFx9DWag4hpSZ", - "publicKey": "e38c9f2760db006f070e9cc1bc1c2269ad033751adaa85d022fb760cbc5b5ef6" - }, - "ocrKeyBundle": { - "bundleID": "99fad0362cc8dc8a57a8e616e68133a6d5a8834e08a1b4819710f0e912df5abc", - "configPublicKey": "36de4924cf11938b4461aea1ce99cb640e9603d9a7c294ab6c54acd51d575a49", - "offchainPublicKey": "283471ed66d61fbe11f64eff65d738b59a0301c9a4f846280db26c64c9fdd3f8", - "onchainSigningAddress": "657587eb55cecd6f90b97297b611c3024e488cc0" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xdAd1F3F8ec690cf335D46c50EdA5547CeF875161", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWR8d5kbZb7YiQWKpT1J1PfMqNaGAmb4jBFx9DWag4hpSZ", - "publicKey": "e38c9f2760db006f070e9cc1bc1c2269ad033751adaa85d022fb760cbc5b5ef6" - }, - "ocrKeyBundle": { - "bundleID": "99fad0362cc8dc8a57a8e616e68133a6d5a8834e08a1b4819710f0e912df5abc", - "configPublicKey": "36de4924cf11938b4461aea1ce99cb640e9603d9a7c294ab6c54acd51d575a49", - "offchainPublicKey": "283471ed66d61fbe11f64eff65d738b59a0301c9a4f846280db26c64c9fdd3f8", - "onchainSigningAddress": "657587eb55cecd6f90b97297b611c3024e488cc0" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:38:35.588611Z" - }, - { - "id": "72", - "keys": [ - "keystone-04" - ], - "name": "Chainlink Keystone Node Operator 4", - "metadata": { - "nodeCount": 2, - "jobCount": 4 - }, - "nodes": [ - { - "id": "785", - "name": "Chainlink Sepolia Prod Keystone One 4", - "publicKey": "07e0ffc57b6263604df517b94bd986169451a3c90600a855bb19212dc575de54", - "chainConfigs": [ - { - "network": { - "id": "1406", - "chainID": "2", - "chainType": "APTOS", - "name": "APTOS TEST" - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWHqR1w26yHatTSZQW3xbRct9SxWzVj9X4SpU916Hy8jYg", - "publicKey": "77224be9d052343b1d17156a1e463625c0d746468d4f5a44cddd452365b1d4ed" - }, - "ocrKeyBundle": { - "bundleID": "b1ab478c1322bc4f8227be50898a8044efc70cf0156ec53cf132119db7e94dea", - "configPublicKey": "96ae354418e50dcd5b3dae62e8f0bc911bbce7f761220837aacdaa6f82bd0f29", - "offchainPublicKey": "b34bb49788541de8b6cfb321799a41927a391a4eb135c74f6cb14eec0531ee6f", - "onchainSigningAddress": "1221e131ef21014a6a99ed22376eb869746a3b5e30fd202cf79e44efaeb8c5c2" - }, - "plugins": {} - } - }, - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x0be7Df958604166D9Bf0F727F0AC7A4Fb0f5B8a1", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWHqR1w26yHatTSZQW3xbRct9SxWzVj9X4SpU916Hy8jYg", - "publicKey": "77224be9d052343b1d17156a1e463625c0d746468d4f5a44cddd452365b1d4ed" - }, - "ocrKeyBundle": { - "bundleID": "8e563a16ec5a802345b162d0f31149e8d5055014a31847d7b20d6de500aa48bd", - "configPublicKey": "c812eab2415f45cc1d2afdb2be2e3ea419bb7851acfc30c07b4df42c856e8f74", - "offchainPublicKey": "2a4c7dec127fdd8145e48c5edb9467225098bd8c8ad1dade868325b787affbde", - "onchainSigningAddress": "a6f35436cb7bffd615cc47a0a04aa0a78696a144" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x6F5cAb24Fb7412bB516b3468b9F3a9c471d25fE5", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWHqR1w26yHatTSZQW3xbRct9SxWzVj9X4SpU916Hy8jYg", - "publicKey": "77224be9d052343b1d17156a1e463625c0d746468d4f5a44cddd452365b1d4ed" - }, - "ocrKeyBundle": { - "bundleID": "8e563a16ec5a802345b162d0f31149e8d5055014a31847d7b20d6de500aa48bd", - "configPublicKey": "c812eab2415f45cc1d2afdb2be2e3ea419bb7851acfc30c07b4df42c856e8f74", - "offchainPublicKey": "2a4c7dec127fdd8145e48c5edb9467225098bd8c8ad1dade868325b787affbde", - "onchainSigningAddress": "a6f35436cb7bffd615cc47a0a04aa0a78696a144" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:39:26.24249Z" - }, - { - "id": "73", - "keys": [ - "keystone-03", - "keystone-bt-03" - ], - "name": "Chainlink Keystone Node Operator 3", - "metadata": { - "nodeCount": 3, - "jobCount": 5 - }, - "nodes": [ - { - "id": "786", - "name": "Chainlink Sepolia Prod Keystone One 3", - "publicKey": "487901e0c0a9d3c66e7cfc50f3a9e3cdbfdf1b0107273d73d94a91d278545516", - "chainConfigs": [ - { - "network": { - "id": "1417", - "chainID": "2", - "chainType": "APTOS", - "name": "APTOS TEST" - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCcVLytqinD8xMn27NvomcQhj2mqMVzyGemz6oPwv1SMT", - "publicKey": "298834a041a056df58c839cb53d99b78558693042e54dff238f504f16d18d4b6" - }, - "ocrKeyBundle": { - "bundleID": "5811a96a0c3b5f5b52973eee10e5771cf5953d37d5616ea71f7ae76f09f6e332", - "configPublicKey": "a7f3435bfbaabebd1572142ff1aec9ed98758d9bb098f1fcc77262fcae7f4171", - "offchainPublicKey": "886044b333af681ab4bf3be663122524ece9725e110ac2a64cda8526cad6983e", - "onchainSigningAddress": "046faf34ebfe42510251e6098bc34fa3dd5f2de38ac07e47f2d1b34ac770639f" - }, - "plugins": {} - } - }, - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x3Be73A57a36E5ab00DcceD755B4bfF8bb99e52b2", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCcVLytqinD8xMn27NvomcQhj2mqMVzyGemz6oPwv1SMT", - "publicKey": "298834a041a056df58c839cb53d99b78558693042e54dff238f504f16d18d4b6" - }, - "ocrKeyBundle": { - "bundleID": "8843b5db0608f92dac38ca56775766a08db9ee82224a19595d04bd6c58b38fbd", - "configPublicKey": "63375a3d175364bd299e7cecf352cb3e469dd30116cf1418f2b7571fb46c4a4b", - "offchainPublicKey": "b4c4993d6c15fee63800db901a8b35fa419057610962caab1c1d7bed55709127", - "onchainSigningAddress": "6607c140e558631407f33bafbabd103863cee876" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xA9eFB53c513E413762b2Be5299D161d8E6e7278e", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCcVLytqinD8xMn27NvomcQhj2mqMVzyGemz6oPwv1SMT", - "publicKey": "298834a041a056df58c839cb53d99b78558693042e54dff238f504f16d18d4b6" - }, - "ocrKeyBundle": { - "bundleID": "8843b5db0608f92dac38ca56775766a08db9ee82224a19595d04bd6c58b38fbd", - "configPublicKey": "63375a3d175364bd299e7cecf352cb3e469dd30116cf1418f2b7571fb46c4a4b", - "offchainPublicKey": "b4c4993d6c15fee63800db901a8b35fa419057610962caab1c1d7bed55709127", - "onchainSigningAddress": "6607c140e558631407f33bafbabd103863cee876" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:40:30.499914Z" - }, - { - "id": "74", - "keys": [ - "keystone-02", - "keystone-bt-02" - ], - "name": "Chainlink Keystone Node Operator 2", - "metadata": { - "nodeCount": 3, - "jobCount": 5 - }, - "nodes": [ - { - "id": "787", - "name": "Chainlink Sepolia Prod Keystone One 2", - "publicKey": "7a166fbc816eb4a4dcb620d11c3ccac5c085d56b1972374100116f87619debb8", - "chainConfigs": [ - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x693bf95A3ef46E5dABe17d1A89dB1E83948aeD88", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWGDmBKZ7B3PynGrvfHTJMEecpjfHts9YK5NWk8oJuxcAo", - "publicKey": "5f247f61a6d5bfdd1d5064db0bd25fe443648133c6131975edb23481424e3d9c" - }, - "ocrKeyBundle": { - "bundleID": "1d20490fe469dd6af3d418cc310a6e835181fa13e8dc80156bcbe302b7afcd34", - "configPublicKey": "ee466234b3b2f65b13c848b17aa6a8d4e0aa0311d3bf8e77a64f20b04ed48d39", - "offchainPublicKey": "dba3c61e5f8bec594be481bcaf67ecea0d1c2950edb15b158ce3dbc77877def3", - "onchainSigningAddress": "d4dcc573e9d24a8b27a07bba670ba3a2ab36e5bb" - }, - "plugins": {} - } - }, - { - "network": { - "id": "1408", - "chainID": "2", - "chainType": "APTOS", - "name": "APTOS TEST" - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWGDmBKZ7B3PynGrvfHTJMEecpjfHts9YK5NWk8oJuxcAo", - "publicKey": "5f247f61a6d5bfdd1d5064db0bd25fe443648133c6131975edb23481424e3d9c" - }, - "ocrKeyBundle": { - "bundleID": "e57c608a899d80e510913d2c7ef55758ee81e9eb73eb531003af1564307fd133", - "configPublicKey": "412a4bed6b064c17168871d28dbb965cc0a898f7b19eb3fa7cd01d3e3d10b66c", - "offchainPublicKey": "450aa794c87198a595761a8c18f0f1590046c8092960036638d002256af95254", - "onchainSigningAddress": "ba20d3da9b07663f1e8039081a514649fd61a48be2d241bc63537ee47d028fcd" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0xCea84bC1881F3cE14BA13Dc3a00DC1Ff3D553fF0", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWGDmBKZ7B3PynGrvfHTJMEecpjfHts9YK5NWk8oJuxcAo", - "publicKey": "5f247f61a6d5bfdd1d5064db0bd25fe443648133c6131975edb23481424e3d9c" - }, - "ocrKeyBundle": { - "bundleID": "1d20490fe469dd6af3d418cc310a6e835181fa13e8dc80156bcbe302b7afcd34", - "configPublicKey": "ee466234b3b2f65b13c848b17aa6a8d4e0aa0311d3bf8e77a64f20b04ed48d39", - "offchainPublicKey": "dba3c61e5f8bec594be481bcaf67ecea0d1c2950edb15b158ce3dbc77877def3", - "onchainSigningAddress": "d4dcc573e9d24a8b27a07bba670ba3a2ab36e5bb" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:41:33.205484Z" - }, - { - "id": "75", - "keys": [ - "keystone-01", - "keystone-bt-01" - ], - "name": "Chainlink Keystone Node Operator 1", - "metadata": { - "nodeCount": 3, - "jobCount": 5 - }, - "nodes": [ - { - "id": "788", - "name": "Chainlink Sepolia Prod Keystone One 1", - "publicKey": "28b91143ec9111796a7d63e14c1cf6bb01b4ed59667ab54f5bc72ebe49c881be", - "chainConfigs": [ - { - "network": { - "id": "1409", - "chainID": "2", - "chainType": "APTOS", - "name": "APTOS TEST" - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCbDiL7sP9BVby5KaZqPpaVP1RBokoa9ShzH5WhkYX46v", - "publicKey": "2934f31f278e5c60618f85861bd6add54a4525d79a642019bdc87d75d26372c3" - }, - "ocrKeyBundle": { - "bundleID": "4b6418b8ab88ea1244c3c48eb5f4c86f9f0301aebffcac4fcfac5cdfb7cf6933", - "configPublicKey": "a38dbe521643479d78ab5477cae78161a5de0030c95098e3fbb09add6aca9508", - "offchainPublicKey": "7718dcbf40173dbd876720aa64028a6b18bf9a87543fc83a549515c4937962e3", - "onchainSigningAddress": "247d0189f65f58be83a4e7d87ff338aaf8956e9acb9fcc783f34f9edc29d1b40" - }, - "plugins": {} - } - }, - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0xe45a754B30FdE9852A826F58c6bd94Fa6554CE96", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCbDiL7sP9BVby5KaZqPpaVP1RBokoa9ShzH5WhkYX46v", - "publicKey": "2934f31f278e5c60618f85861bd6add54a4525d79a642019bdc87d75d26372c3" - }, - "ocrKeyBundle": { - "bundleID": "7a9b75510b8d09932b98142419bef52436ff725dd9395469473b487ef87fdfb0", - "configPublicKey": "2c45fec2320f6bcd36444529a86d9f8b4439499a5d8272dec9bcbbebb5e1bf01", - "offchainPublicKey": "255096a3b7ade10e29c648e0b407fc486180464f713446b1da04f013df6179c8", - "onchainSigningAddress": "8258f4c4761cc445333017608044a204fd0c006a" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x415aa1E9a1bcB3929ed92bFa1F9735Dc0D45AD31", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWCbDiL7sP9BVby5KaZqPpaVP1RBokoa9ShzH5WhkYX46v", - "publicKey": "2934f31f278e5c60618f85861bd6add54a4525d79a642019bdc87d75d26372c3" - }, - "ocrKeyBundle": { - "bundleID": "7a9b75510b8d09932b98142419bef52436ff725dd9395469473b487ef87fdfb0", - "configPublicKey": "2c45fec2320f6bcd36444529a86d9f8b4439499a5d8272dec9bcbbebb5e1bf01", - "offchainPublicKey": "255096a3b7ade10e29c648e0b407fc486180464f713446b1da04f013df6179c8", - "onchainSigningAddress": "8258f4c4761cc445333017608044a204fd0c006a" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:42:05.709664Z" - }, - { - "id": "76", - "keys": [ - "keystone-00", - "keystone-bt-00" - ], - "name": "Chainlink Keystone Node Operator 0", - "metadata": { - "nodeCount": 3, - "jobCount": 5 - }, - "nodes": [ - { - "id": "789", - "name": "Chainlink Sepolia Prod Keystone One 0", - "publicKey": "403b72f0b1b3b5f5a91bcfedb7f28599767502a04b5b7e067fcf3782e23eeb9c", - "chainConfigs": [ - { - "network": { - "id": "1411", - "chainID": "2", - "chainType": "APTOS", - "name": "APTOS TEST" - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMWUKdoAc2ruZf9f55p7NVFj7AFiPm67xjQ8BZBwkqyYv", - "publicKey": "adb6bf005cdb23f21e11b82d66b9f62628c2939640ed93028bf0dad3923c5a8b" - }, - "ocrKeyBundle": { - "bundleID": "b4504e84ea307cc2afffca0206bd4bf8e98acc5a03c9bd47b2456e3845a5d1fa", - "configPublicKey": "559ea4ee5774a31d97914a4220d6a47094ae8e2cf0806e80e1eacd851f3e6757", - "offchainPublicKey": "4ec55bbe76a6b1fdc885c59da85a8fe44cf06afe1e4719f0824a731937526c52", - "onchainSigningAddress": "b8834eaa062f0df4ccfe7832253920071ec14dc4f78b13ecdda10b824e2dd3b6" - }, - "plugins": {} - } - }, - { - "network": { - "id": "140", - "chainID": "421614", - "chainType": "EVM", - "name": "Arbitrum Testnet (Sepolia)" - }, - "accountAddress": "0x1a04C6b4b1A45D20356F93DcE7931F765955BAa7", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMWUKdoAc2ruZf9f55p7NVFj7AFiPm67xjQ8BZBwkqyYv", - "publicKey": "adb6bf005cdb23f21e11b82d66b9f62628c2939640ed93028bf0dad3923c5a8b" - }, - "ocrKeyBundle": { - "bundleID": "665a101d79d310cb0a5ebf695b06e8fc8082b5cbe62d7d362d80d47447a31fea", - "configPublicKey": "5193f72fc7b4323a86088fb0acb4e4494ae351920b3944bd726a59e8dbcdd45f", - "offchainPublicKey": "03dacd15fc96c965c648e3623180de002b71a97cf6eeca9affb91f461dcd6ce1", - "onchainSigningAddress": "b35409a8d4f9a18da55c5b2bb08a3f5f68d44442" - }, - "plugins": {} - } - }, - { - "network": { - "id": "129", - "chainID": "11155111", - "chainType": "EVM", - "name": "Ethereum Testnet (Sepolia)" - }, - "accountAddress": "0x2877F08d9c5Cc9F401F730Fa418fAE563A9a2FF3", - "adminAddress": "0x0000000000000000000000000000000000000000", - "ocr1Config": { - "p2pKeyBundle": {}, - "ocrKeyBundle": {} - }, - "ocr2Config": { - "enabled": true, - "p2pKeyBundle": { - "peerID": "p2p_12D3KooWMWUKdoAc2ruZf9f55p7NVFj7AFiPm67xjQ8BZBwkqyYv", - "publicKey": "adb6bf005cdb23f21e11b82d66b9f62628c2939640ed93028bf0dad3923c5a8b" - }, - "ocrKeyBundle": { - "bundleID": "665a101d79d310cb0a5ebf695b06e8fc8082b5cbe62d7d362d80d47447a31fea", - "configPublicKey": "5193f72fc7b4323a86088fb0acb4e4494ae351920b3944bd726a59e8dbcdd45f", - "offchainPublicKey": "03dacd15fc96c965c648e3623180de002b71a97cf6eeca9affb91f461dcd6ce1", - "onchainSigningAddress": "b35409a8d4f9a18da55c5b2bb08a3f5f68d44442" - }, - "plugins": {} - } - } - ], - "connected": true, - "supportedProducts": [ - "WORKFLOW", - "OCR3_CAPABILITY" - ], - "categories": [ - { - "id": "11", - "name": "Keystone" - } - ] - } - ], - "createdAt": "2024-08-14T20:42:49.446864Z" - } -] From 8cc06ab89aa49555e967ec7d188b8d0bbb5ee36e Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 18 Dec 2024 12:05:54 -0600 Subject: [PATCH 20/27] deployment: add context lint rules (#15413) * deployment: add context lint rules * Update golanci-lint-action to scan all affected directories and correctly upload reports Update golangci-lint action to go through all dirs if no working directory set Update paths to linter reports Restore producing test coverage report for each unit test run Remove test files fail_test.go and polished the workflows Get list of affected files Map affected files to modules Update lint working directory for uploading step Update lint working directory for uploading step Removed duplicated runs of golangci-lint Move running tests for core/scripts module to ci-core.yaml workflow Remove test files Move validation of golangci results to a non-matrix job Add filter for affected files in core/scripts. Move related tests to a separate job Update SonarQube to pick up coverage reports for core/scripts test runs --------- Co-authored-by: Alexandr Yepishev --- .github/actions/golangci-lint/action.yml | 60 +++++-- .../scripts/map-affected-files-to-modules.sh | 50 ++++++ .github/workflows/ci-core.yml | 148 ++++++++++++++---- .github/workflows/ci-scripts.yml | 41 ----- .github/workflows/integration-tests.yml | 50 +----- ...cability.yml => solidity-traceability.yml} | 2 +- .gitignore | 3 +- .golangci.yml | 1 + .tool-versions | 3 +- GNUmakefile | 2 +- deployment/.golangci.yml | 3 + tools/bin/go_core_scripts_tests | 36 +++++ tools/bin/go_core_tests | 2 +- 13 files changed, 266 insertions(+), 135 deletions(-) create mode 100755 .github/scripts/map-affected-files-to-modules.sh delete mode 100644 .github/workflows/ci-scripts.yml rename .github/workflows/{solidity-tracability.yml => solidity-traceability.yml} (99%) create mode 100755 tools/bin/go_core_scripts_tests diff --git a/.github/actions/golangci-lint/action.yml b/.github/actions/golangci-lint/action.yml index 20ad2689deb..22a35682c2d 100644 --- a/.github/actions/golangci-lint/action.yml +++ b/.github/actions/golangci-lint/action.yml @@ -27,11 +27,13 @@ runs: if: github.event_name == 'merge_group' with: fetch-depth: 0 + - name: Checkout repo uses: actions/checkout@v4.2.1 if: github.event_name != 'merge_group' with: fetch-depth: 1 + - name: Setup Go uses: ./.github/actions/setup-go with: @@ -39,38 +41,66 @@ runs: cache-version: ${{ inputs.cache-version }} go-version-file: ${{ inputs.go-version-file }} go-module-file: ${{ inputs.go-module-file }} + - name: Touching core/web/assets/index.html shell: bash run: mkdir -p core/web/assets && touch core/web/assets/index.html - - name: Build binary - working-directory: ${{ inputs.go-directory }} - shell: bash - run: go build ./... - - name: Set golangci-lint working directory + + - name: Set Golangci-lint working directory shell: bash id: set-working-directory # XXX: Don't use `.` default working directory here due to issues with the golangci-lint-action. run: | if [ "${{ inputs.go-directory }}" == "." ]; then - echo "golangci-lint-working-directory=" | tee -a $GITHUB_OUTPUT + echo "golangci-lint-working-directory=" >> $GITHUB_OUTPUT else - echo "golangci-lint-working-directory=${{ inputs.go-directory }}" | tee -a $GITHUB_OUTPUT + echo "golangci-lint-working-directory=${{ inputs.go-directory }}/" >> $GITHUB_OUTPUT fi - - name: golangci-lint + + - name: Golangci-lint uses: golangci/golangci-lint-action@38e1018663fa5173f3968ea0777460d3de38f256 # v5.3.0 with: - version: v1.61.0 + version: v1.62.2 only-new-issues: true args: --out-format colored-line-number,checkstyle:golangci-lint-report.xml working-directory: ${{ steps.set-working-directory.outputs.golangci-lint-working-directory }} - - name: Print lint report artifact + + - name: Print Golangci-lint report results if: failure() shell: bash - run: cat ${{ inputs.go-directory }}/golangci-lint-report.xml - - name: Store lint report artifact + run: cat ./${{ steps.set-working-directory.outputs.golangci-lint-working-directory }}golangci-lint-report.xml + + # Get a valid name for the upload-artifact step. + # Avoid error: `The artifact name is not valid: ///` caused by `/`. + # Remove trailing `/` from the directory name: `core/scripts/` -> `core/scripts`. + # Replace remaining `/` with `-`: `core/scripts` -> `core-scripts`. + # Assign `root` if the directory name is empty (ref: step.id: set-working-directory). + - name: Get valid suffix for artifact name + if: always() + id: suffix + shell: bash + run: | + go_directory=${{ steps.set-working-directory.outputs.golangci-lint-working-directory }} + echo "Validating if directory name '$go_directory' is empty or has slashes" + + if [[ $go_directory == *\/* ]]; then + suffix=$(echo "$go_directory" | sed 's:\/$::' | tr '/' '-') + echo "Directory name with slashes '$go_directory' updated to a valid artifact suffix '$suffix'" + elif [[ $go_directory == "" ]]; then + suffix="root" + echo "Root directory (empty string) updated to a valid artifact suffix '$suffix'" + else + suffix="$go_directory" + echo "Directory name is valid for the artifact suffix: '$suffix'" + fi + + echo "suffix=${suffix}" >> $GITHUB_OUTPUT + + - name: Store Golangci-lint report artifact if: always() uses: actions/upload-artifact@v4.4.3 with: - name: golangci-lint-report - path: ${{ inputs.go-directory }}/golangci-lint-report.xml - retention-days: 7 + # Use a unique suffix for each lint report artifact to avoid duplication errors + name: golangci-lint-report-${{ steps.suffix.outputs.suffix }} + # N/B: value may be empty (no slash) OR `///` (with slash tat the end) + path: ./${{ steps.set-working-directory.outputs.golangci-lint-working-directory }}golangci-lint-report.xml diff --git a/.github/scripts/map-affected-files-to-modules.sh b/.github/scripts/map-affected-files-to-modules.sh new file mode 100755 index 00000000000..a12e5306894 --- /dev/null +++ b/.github/scripts/map-affected-files-to-modules.sh @@ -0,0 +1,50 @@ +#!/bin/bash +set -e + +# This script: +# 1. Finds all modules. +# 2. Maps changed files (passed as a param) to found modules. +# 3. Prints out the affected modules. +# 4. Output the result (as JSON) to a GitHub Actions environment variable. + +# Get the list of changed files as parameter (from JSON array) +changed_files=$(echo "$1" | jq -r '.[]') +echo "Changed files: $changed_files" + +# 1. Find all modules in the repository, +# - Strip the leading './' from the path +# (necessary for comparison, affected files do not have leading './') +modules=$(find . -name 'go.mod' -exec dirname {} \; | sed 's|^./||' | uniq) +echo "Found modules: $modules" + +# Use a Bash associative array to track unique modules +declare -A unique_modules + +for path_to_file in $changed_files; do + echo "Resolving a module affected by a file: '$path_to_file'" + for module in $modules; do + echo "Validating against module: '$module'" + + # if no slash in the path, it is the root + # (i.e. `main.go`, `.gitignore` vs `core/main.go`) + if [[ ! $path_to_file =~ \/ ]]; then + echo "File '$path_to_file' mapped to the "root" module." + unique_modules["."]="." + break + # if a module's name matches with a file path + # add it, to the affected modules array, skipping the root (`.`) + elif [[ $module != "." && $path_to_file =~ ^$module* ]]; then + echo "File '$path_to_file' mapped the module '$module'" + unique_modules["$module"]="$module" + break + fi + done +done + +# Convert keys (module names) of the associative array to an indexed array +affected_modules=("${!unique_modules[@]}") +echo "Affected modules: ${affected_modules[@]}" + +# Convert bash array to a JSON array for GitHub Actions +json_array=$(printf '%s\n' "${affected_modules[@]}" | jq -R . | jq -s . | jq -c) +echo "module_names=$json_array" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index 726b6b14074..882d40425eb 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -33,7 +33,9 @@ jobs: permissions: pull-requests: read outputs: + affected-packages: ${{ steps.resolved-modules.outputs.module_names }} deployment-changes: ${{ steps.match-some.outputs.deployment == 'true' }} + scripts-changes: ${{ steps.match-some.outputs.scripts == 'true' }} should-run-ci-core: ${{ steps.match-some.outputs.core-ci == 'true' || steps.match-every.outputs.non-ignored == 'true' || github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' }} should-run-golangci: ${{ steps.match-some.outputs.golang-ci == 'true' || steps.match-every.outputs.non-ignored == 'true' || github.event_name == 'workflow_dispatch' }} runs-on: ubuntu-latest @@ -47,7 +49,8 @@ jobs: with: # "if any changed file matches one or more of the conditions" (https://github.com/dorny/paths-filter/issues/225) predicate-quantifier: some - # deployment - any changes to files in `deployments/` + # deployment - any changes to files in the `deployments/` + # scripts - any changes to files in the `core/scripts/` # core-ci - any changes that could affect this workflow definition # golang-ci - any changes that could affect the linting result filters: | @@ -60,6 +63,8 @@ jobs: - '.golangci.yml' - '.github/workflows/ci-core.yml' - '.github/actions/**' + scripts: + - 'core/scripts/**' - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 id: match-every with: @@ -67,14 +72,18 @@ jobs: predicate-quantifier: every # non-integration-tests - only changes made outside of the `integration-tests` directory # non-ignored - only changes except for the negated ones + # all - changes in any directory # - This is opt-in on purpose. To be safe, new files are assumed to have an affect on CI Core unless listed here specifically. + # Enable listing of files matching each filter. + # Paths to files will be available in `${FILTER_NAME}_files` output variable. + # Paths will be formatted as JSON array + list-files: json filters: | non-integration-tests: - '**' - '!integration-tests/**' non-ignored: - '**' - - '!docs/**' - '!integration-tests/**' - '!tools/secrets/**' - '!tools/goreleaser-config/**' @@ -91,24 +100,39 @@ jobs: - '!nix-darwin-shell-hook.sh' - '!LICENSE' - '!.github/**' - + all: + - '**' + + - name: Resolve affected files to affected modules + id: resolved-modules + shell: bash + run: | + # Ensure the step uses `with.list-files: json` to get the list of files in JSON format + bash ./.github/scripts/map-affected-files-to-modules.sh '${{ steps.match-every.outputs.all_files }}' + golangci: - # We don't directly merge dependabot PRs, so let's not waste the resources + name: GolangCI Lint + needs: [filter, run-frequency] + # We don't directly merge dependabot PRs to not waste the resources. if: ${{ (github.event_name == 'pull_request' || github.event_name == 'schedule') && github.actor != 'dependabot[bot]' }} - name: lint permissions: - # For golangci-lint-actions to annotate code in the PR. + # To annotate code in the PR. checks: write contents: read # For golangci-lint-action's `only-new-issues` option. pull-requests: read runs-on: ubuntu-24.04-8cores-32GB-ARM - needs: [filter, run-frequency] + strategy: + fail-fast: false + matrix: + modules: ${{ fromJson(needs.filter.outputs.affected-packages) }} steps: - - uses: actions/checkout@v4.2.1 - - name: Golang Lint + - name: Checkout + uses: actions/checkout@v4.2.1 + - name: Golang Lint (${{ matrix.modules }}) uses: ./.github/actions/golangci-lint - if: ${{ needs.filter.outputs.should-run-golangci == 'true' }} + with: + go-directory: ${{ matrix.modules }} - name: Notify Slack if: ${{ failure() && needs.run-frequency.outputs.one-per-day-frequency == 'true' }} uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0 @@ -117,6 +141,22 @@ jobs: with: channel-id: "#team-core" slack-message: "golangci-lint failed: \n${{ format('https://github.com/{0}/actions/runs/{1}', github.repository, github.run_id) }}" + + # Fails if any golangci-lint matrix jobs fails and silently succeeds otherwise + # Consolidates golangci-lint matrix job results under one required `lint` check + # Inclusive check: all (new) modules are analyzed, but no need to enable "required" checks for each one + golangci-matrix-results-validation: + name: lint + needs: [golangci] + # We don't directly merge dependabot PRs to not waste the resources. + if: ${{ (github.event_name == 'pull_request' || github.event_name == 'schedule') && github.actor != 'dependabot[bot]' }} + runs-on: ubuntu-latest + steps: + - name: Check Golangci-lint Matrix Results + if: ${{ needs.golangci.result != 'success' }} + run: | + echo "At least one 'GolangCI Lint' matrix job failed. Check the failed lint jobs." + exit 1 core: env: @@ -136,11 +176,11 @@ jobs: - cmd: go_core_ccip_deployment_tests os: ubuntu22.04-32cores-128GB printResults: true + - cmd: go_core_fuzz + os: ubuntu22.04-8cores-32GB - cmd: go_core_race_tests # use 64cores for certain scheduled runs only os: ${{ needs.run-frequency.outputs.two-per-day-frequency == 'true' && 'ubuntu-latest-64cores-256GB' || 'ubuntu-latest-32cores-128GB' }} - - cmd: go_core_fuzz - os: ubuntu22.04-8cores-32GB name: Core Tests (${{ matrix.type.cmd }}) # We don't directly merge dependabot PRs, so let's not waste the resources if: ${{ github.actor != 'dependabot[bot]' }} @@ -285,8 +325,38 @@ jobs: channel-id: "#topic-data-races" slack-message: "Race tests failed: \n${{ format('https://github.com/{0}/actions/runs/{1}', github.repository, github.run_id) }}" + core-scripts-tests: + name: test-scripts + needs: [filter] + runs-on: ubuntu-latest + if: ${{ github.event_name == 'schedule' || needs.filter.outputs.scripts-changes == 'true' }} + steps: + - name: Checkout + uses: actions/checkout@v4.2.1 + + - name: Setup Go + uses: ./.github/actions/setup-go + with: + go-version-file: core/scripts/go.mod + go-module-file: core/scripts/go.sum + + - name: Run Tests + env: + OUTPUT_FILE: ./output.txt + run: ./tools/bin/go_core_scripts_tests ./... + + - name: Store test report artifacts + if: ${{ always() && needs.filter.outputs.should-run-ci-core == 'true' }} + uses: actions/upload-artifact@v4.4.3 + with: + name: go_core_scripts_tests_logs + path: | + ./output.txt + ./coverage.txt + retention-days: 7 + detect-flakey-tests: - needs: [filter, core] + needs: [filter, core, core-scripts-tests] name: Flakey Test Detection runs-on: ubuntu-latest if: always() && (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') @@ -375,8 +445,8 @@ jobs: scan: name: SonarQube Scan - needs: [core, run-frequency] - if: ${{ always() && needs.run-frequency.outputs.four-per-day-frequency == 'true' && github.actor != 'dependabot[bot]' }} + needs: [golangci, core, core-scripts-tests] + if: ${{ always() && github.actor != 'dependabot[bot]' }} runs-on: ubuntu-latest steps: - name: Checkout the repo @@ -384,37 +454,61 @@ jobs: with: fetch-depth: 0 # fetches all history for all tags and branches to provide more metadata for sonar reports - - name: Download all workflow run artifacts + - name: Download all workflow artifacts uses: actions/download-artifact@v4.1.8 - name: Check and Set SonarQube Report Paths shell: bash run: | # Check and assign paths for coverage/test reports in go_core_tests_logs - if [ -d "go_core_tests_logs" ]; then - sonarqube_coverage_report_paths=$(find go_core_tests_logs -name coverage.txt | paste -sd "," -) - sonarqube_tests_report_paths=$(find go_core_tests_logs -name output.txt | paste -sd "," -) + core_artifact="go_core_tests_logs" + if [ -d "$core_artifact" ]; then + echo "Found $core_artifact" + sonarqube_coverage_report_paths=$(find "$core_artifact" -name coverage.txt | paste -sd "," -) + sonarqube_tests_report_paths=$(find "$core_artifact" -name output.txt | paste -sd "," -) + echo "Coverage report paths: $sonarqube_coverage_report_paths" + echo "Tests report paths: $sonarqube_tests_report_paths" else + echo "Did not find $core_artifact" sonarqube_coverage_report_paths="" sonarqube_tests_report_paths="" fi # Check and assign paths for coverage/test reports in go_core_tests_integration_logs - if [ -d "go_core_tests_integration_logs" ]; then - integration_coverage_paths=$(find go_core_tests_integration_logs -name coverage.txt | paste -sd "," -) - integration_tests_paths=$(find go_core_tests_integration_logs -name output.txt | paste -sd "," -) + integration_tests_artifact="go_core_tests_integration_logs" + if [ -d "$integration_tests_artifact" ]; then + echo "Found $integration_tests_artifact" + integration_coverage_paths=$(find "$integration_tests_artifact" -name coverage.txt | paste -sd "," -) + integration_tests_paths=$(find "$integration_tests_artifact" -name output.txt | paste -sd "," -) + # Append to existing paths if they are set, otherwise assign directly sonarqube_coverage_report_paths="${sonarqube_coverage_report_paths:+$sonarqube_coverage_report_paths,}$integration_coverage_paths" sonarqube_tests_report_paths="${sonarqube_tests_report_paths:+$sonarqube_tests_report_paths,}$integration_tests_paths" fi - # Check and assign paths for lint reports - if [ -d "golangci-lint-report" ]; then - sonarqube_lint_report_paths=$(find golangci-lint-report -name golangci-lint-report.xml | paste -sd "," -) - else - sonarqube_lint_report_paths="" + # Check and assign paths for coverage/test reports in go_core_scripts_tests_logs + scripts_tests_artifact="go_core_scripts_tests_logs" + if [ -d "$scripts_tests_artifact" ]; then + echo "Found $scripts_tests_artifact" + scripts_coverage_paths=$(find "$scripts_tests_artifact" -name coverage.txt | paste -sd "," -) + scripts_tests_paths=$(find "$scripts_tests_artifact" -name output.txt | paste -sd "," -) + + # Append to existing paths if they are set, otherwise assign directly + sonarqube_coverage_report_paths="${sonarqube_coverage_report_paths:+$sonarqube_coverage_report_paths,}$scripts_coverage_paths" + sonarqube_tests_report_paths="${sonarqube_tests_report_paths:+$sonarqube_tests_report_paths,}$scripts_tests_paths" fi + # Check and assign paths for lint reports + # To find reports in the folders named differently (because of the matrix strategy), + # We need to loop through the artifacts. It allows usage of RegExp folders (skipped if not found). + for golang_lint_artifact in golangci-lint-report* + do + echo "Found golangci-lint-report artifacts" + sonarqube_lint_report_paths=$(find -type f -name 'golangci-lint-report.xml' -printf "%p,") + echo "Lint report paths: $sonarqube_lint_report_paths" + break + done + ARGS="" if [[ -z "$sonarqube_tests_report_paths" ]]; then echo "::warning::No test report paths found, will not pass to sonarqube" diff --git a/.github/workflows/ci-scripts.yml b/.github/workflows/ci-scripts.yml deleted file mode 100644 index 5683641f26b..00000000000 --- a/.github/workflows/ci-scripts.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: CI Scripts - -on: - merge_group: - pull_request: - -jobs: - lint-scripts: - # We don't directly merge dependabot PRs, so let's not waste the resources - if: ${{ (github.event_name == 'pull_request' || github.event_name == 'schedule') && github.actor != 'dependabot[bot]' }} - runs-on: ubuntu-latest - permissions: - # For golangci-lint-actions to annotate code in the PR. - checks: write - contents: read - # For golangci-lint-action's `only-new-issues` option. - pull-requests: read - steps: - - uses: actions/checkout@v4.2.1 - - name: Golang Lint - uses: ./.github/actions/golangci-lint - with: - id: scripts - name: lint-scripts - go-directory: core/scripts - go-version-file: core/scripts/go.mod - go-module-file: core/scripts/go.sum - - test-scripts: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4.2.1 - - name: Setup Go - uses: ./.github/actions/setup-go - with: - go-version-file: core/scripts/go.mod - go-module-file: core/scripts/go.sum - - name: Run Tests - shell: bash - working-directory: core/scripts - run: go test ./... diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 27bdfa52243..e79956cc253 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -1,3 +1,5 @@ +# N/B: ci-core, which runs on PRs, will trigger linting for affected directories/modules +# no need to run lint twice name: Integration Tests run-name: Integration Tests ${{ inputs.distinct_run_name && inputs.distinct_run_name || '' }} on: @@ -116,47 +118,6 @@ jobs: core_changes: ${{ steps.ignore-filter.outputs.changes || steps.changes.outputs.core_changes }} ccip_changes: ${{ steps.ignore-filter.outputs.changes || steps.changes.outputs.ccip_changes }} - lint-integration-tests: - name: Lint ${{ matrix.project.name }} - runs-on: ubuntu-24.04-8cores-32GB-ARM - # We don't directly merge dependabot PRs, so let's not waste the resources - if: github.actor != 'dependabot[bot]' - strategy: - matrix: - project: - - name: integration-tests - id: e2e-tests - path: ./integration-tests - cache_id: e2e-tests - - name: load - id: load - path: ./integration-tests/load - cache_id: load - steps: - - name: Checkout the repo - uses: actions/checkout@v4.2.1 - with: - repository: smartcontractkit/chainlink - ref: ${{ inputs.cl_ref }} - - name: Setup Go - uses: smartcontractkit/.github/actions/ctf-setup-go@b0d756c57fcdbcff187e74166562a029fdd5d1b9 # ctf-setup-go@0.0.0 - with: - test_download_vendor_packages_command: cd ${{ matrix.project.path }} && go mod download - go_mod_path: ${{ matrix.project.path }}/go.mod - cache_key_id: ${{ matrix.project.cache_id }} - cache_restore_only: "true" - - name: Lint Go - uses: golangci/golangci-lint-action@3cfe3a4abbb849e10058ce4af15d205b6da42804 # v4.0.0 - with: - version: v1.62.0 - # We already cache these directories in setup-go - skip-pkg-cache: true - skip-build-cache: true - # only-new-issues is only applicable to PRs, otherwise it is always set to false - only-new-issues: false # disabled for PRs due to unreliability - args: --out-format colored-line-number,checkstyle:golangci-lint-report.xml - working-directory: ${{ matrix.project.path }} - build-chainlink: environment: integration permissions: @@ -171,6 +132,7 @@ jobs: - name: (plugins) dockerfile: plugins/chainlink.Dockerfile tag-suffix: -plugins + name: Build Chainlink Image ${{ matrix.image.name }} runs-on: ubuntu22.04-8cores-32GB needs: [changes, enforce-ctf-version] @@ -374,7 +336,7 @@ jobs: if: always() name: ETH Smoke Tests runs-on: ubuntu-latest - needs: [lint-integration-tests, run-core-e2e-tests-for-pr, run-ccip-e2e-tests-for-pr, run-core-e2e-tests-for-merge-queue, run-ccip-e2e-tests-for-merge-queue] + needs: [run-core-e2e-tests-for-pr, run-ccip-e2e-tests-for-pr, run-core-e2e-tests-for-merge-queue, run-ccip-e2e-tests-for-merge-queue] steps: - name: Check Core test results id: check_core_results @@ -414,10 +376,6 @@ jobs: if: always() && needs.run-core-e2e-tests-for-merge-queue.result == 'failure' run: exit 1 - - name: Fail the job if lint not successful - if: always() && needs.lint-integration-tests.result == 'failure' - run: exit 1 - cleanup: name: Clean up integration environment deployments if: always() diff --git a/.github/workflows/solidity-tracability.yml b/.github/workflows/solidity-traceability.yml similarity index 99% rename from .github/workflows/solidity-tracability.yml rename to .github/workflows/solidity-traceability.yml index f0b1166807f..caa233ea8bb 100644 --- a/.github/workflows/solidity-tracability.yml +++ b/.github/workflows/solidity-traceability.yml @@ -1,5 +1,5 @@ # This workflow handles the enforcement of code Traceability via changesets and jira issue linking for our Solidity codebase. -name: Solidity Tracability +name: Solidity Traceability on: merge_group: diff --git a/.gitignore b/.gitignore index 34d25ebb472..af19562c928 100644 --- a/.gitignore +++ b/.gitignore @@ -48,9 +48,8 @@ cl_backup_*.tar.gz # Test artifacts core/cmd/TestClient_ImportExportP2PKeyBundle_test_key.json -output.txt race.* -golangci-lint-output.txt +*output.txt /golangci-lint/ .covdata core/services/job/testdata/wasm/testmodule.wasm diff --git a/.golangci.yml b/.golangci.yml index ca8cf4dade5..a7928ee97de 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,5 +1,6 @@ run: timeout: 15m0s + allow-parallel-runners: true linters: enable: - containedctx diff --git a/.tool-versions b/.tool-versions index 49f7ef749d1..bdf11a7ed21 100644 --- a/.tool-versions +++ b/.tool-versions @@ -4,6 +4,7 @@ nodejs 20.13.1 pnpm 9.4.0 postgres 15.1 helm 3.10.3 -golangci-lint 1.61.0 +golangci-lint 1.62.2 protoc 25.1 python 3.10.5 +act 0.2.30 diff --git a/GNUmakefile b/GNUmakefile index 470d41c697b..08324b1fec4 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -174,7 +174,7 @@ config-docs: ## Generate core node configuration documentation .PHONY: golangci-lint golangci-lint: ## Run golangci-lint for all issues. [ -d "./golangci-lint" ] || mkdir ./golangci-lint && \ - docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.61.0 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 | tee ./golangci-lint/$(shell date +%Y-%m-%d_%H:%M:%S).txt + docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.62.2 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 | tee ./golangci-lint/$(shell date +%Y-%m-%d_%H:%M:%S).txt .PHONY: modgraph modgraph: diff --git a/deployment/.golangci.yml b/deployment/.golangci.yml index 0268ba7beaa..4a2e2b4a47c 100644 --- a/deployment/.golangci.yml +++ b/deployment/.golangci.yml @@ -10,6 +10,9 @@ linters: - misspell - rowserrcheck - errorlint + - containedctx + - fatcontext + - noctx linters-settings: exhaustive: default-signifies-exhaustive: true diff --git a/tools/bin/go_core_scripts_tests b/tools/bin/go_core_scripts_tests new file mode 100755 index 00000000000..e4380264215 --- /dev/null +++ b/tools/bin/go_core_scripts_tests @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -o pipefail +set +e + +SCRIPT_PATH=`dirname "$0"`; SCRIPT_PATH=`eval "cd \"$SCRIPT_PATH\" && pwd"` +OUTPUT_FILE=${OUTPUT_FILE:-"./output.txt"} +EXTRA_FLAGS="" + +cd ./core/scripts || exit +go mod download +echo "Test execution results: ---------------------" +echo "" + +if [[ $GITHUB_EVENT_NAME == "schedule" ]]; then + EXTRA_FLAGS="-covermode=atomic -coverpkg=./... -coverprofile=coverage.txt" +fi +go test ./... $EXTRA_FLAGS | tee $OUTPUT_FILE | grep -Ev '\[no test files\]|\[no tests to run\]' +EXITCODE=${PIPESTATUS[0]} + +# Assert no known sensitive strings present in test logger output +printf "\n----------------------------------------------\n\n" +echo "Beginning check of output logs for sensitive strings" +$SCRIPT_PATH/scrub_logs $OUTPUT_FILE +cd .. +if [[ $? != 0 ]]; then + exit 1 +fi + +echo "Exit code: $EXITCODE" +if [[ $EXITCODE != 0 ]]; then + echo "Encountered test failures." +else + echo "All tests passed!" +fi +echo "go_core_scripts_tests exiting with code $EXITCODE" +exit $EXITCODE diff --git a/tools/bin/go_core_tests b/tools/bin/go_core_tests index 76c15fccd07..3679988a896 100755 --- a/tools/bin/go_core_tests +++ b/tools/bin/go_core_tests @@ -29,4 +29,4 @@ else echo "All tests passed!" fi echo "go_core_tests exiting with code $EXITCODE" -exit $EXITCODE +exit $EXITCODE \ No newline at end of file From e1b27f3516040a719a206846fdcd19384b3f27d1 Mon Sep 17 00:00:00 2001 From: Connor Stein Date: Wed, 18 Dec 2024 13:21:17 -0500 Subject: [PATCH 21/27] Granular MCMS optional CCIP chain contract changesets (#15651) * Wip * Wip * offramp source updates * wip * Finish router * FQ updates * Initial router test * Chain config update cs * Add multi-don home changesets * Test helpers working using changesets * Extract stuff from initial add chain * Remove some duplicate code * Need offramp set * Fix order * Fix imports add ownership validation * More ownership validation * Move to common * Renaming --- .../ccip/changeset/accept_ownership_test.go | 2 + deployment/ccip/changeset/cs_add_chain.go | 173 ---- .../ccip/changeset/cs_add_chain_test.go | 335 -------- deployment/ccip/changeset/cs_ccip_home.go | 749 ++++++++++++----- .../ccip/changeset/cs_ccip_home_test.go | 195 ++++- .../ccip/changeset/cs_chain_contracts.go | 757 ++++++++++++++++++ .../ccip/changeset/cs_chain_contracts_test.go | 305 +++++++ .../ccip/changeset/cs_initial_add_chain.go | 532 ------------ .../changeset/cs_initial_add_chain_test.go | 93 --- .../changeset/internal/deploy_home_chain.go | 255 +----- deployment/ccip/changeset/state.go | 8 + deployment/ccip/changeset/test_assertions.go | 17 + deployment/ccip/changeset/test_environment.go | 93 ++- .../changeset/deploy_mcms_with_timelock.go | 19 + deployment/common/proposalutils/propose.go | 8 +- 15 files changed, 1899 insertions(+), 1642 deletions(-) delete mode 100644 deployment/ccip/changeset/cs_add_chain.go delete mode 100644 deployment/ccip/changeset/cs_add_chain_test.go create mode 100644 deployment/ccip/changeset/cs_chain_contracts.go create mode 100644 deployment/ccip/changeset/cs_chain_contracts_test.go delete mode 100644 deployment/ccip/changeset/cs_initial_add_chain.go delete mode 100644 deployment/ccip/changeset/cs_initial_add_chain_test.go diff --git a/deployment/ccip/changeset/accept_ownership_test.go b/deployment/ccip/changeset/accept_ownership_test.go index 9b71e0ad5cb..f74556b6600 100644 --- a/deployment/ccip/changeset/accept_ownership_test.go +++ b/deployment/ccip/changeset/accept_ownership_test.go @@ -70,6 +70,8 @@ func genTestTransferOwnershipConfig( state.Chains[chain].FeeQuoter.Address(), state.Chains[chain].NonceManager.Address(), state.Chains[chain].RMNRemote.Address(), + state.Chains[chain].TestRouter.Address(), + state.Chains[chain].Router.Address(), } } diff --git a/deployment/ccip/changeset/cs_add_chain.go b/deployment/ccip/changeset/cs_add_chain.go deleted file mode 100644 index ddb6e61d5ba..00000000000 --- a/deployment/ccip/changeset/cs_add_chain.go +++ /dev/null @@ -1,173 +0,0 @@ -package changeset - -import ( - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/common" - - "github.com/smartcontractkit/chainlink-ccip/chainconfig" - "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" - "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" - - "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" - - "github.com/smartcontractkit/chainlink/deployment" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_home" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" -) - -var _ deployment.ChangeSet[ChainInboundChangesetConfig] = NewChainInboundChangeset - -type ChainInboundChangesetConfig struct { - HomeChainSelector uint64 - NewChainSelector uint64 - SourceChainSelectors []uint64 -} - -func (c ChainInboundChangesetConfig) Validate() error { - if c.HomeChainSelector == 0 { - return fmt.Errorf("HomeChainSelector must be set") - } - if c.NewChainSelector == 0 { - return fmt.Errorf("NewChainSelector must be set") - } - if len(c.SourceChainSelectors) == 0 { - return fmt.Errorf("SourceChainSelectors must be set") - } - return nil -} - -// NewChainInboundChangeset generates a proposal -// to connect the new chain to the existing chains. -func NewChainInboundChangeset( - e deployment.Environment, - cfg ChainInboundChangesetConfig, -) (deployment.ChangesetOutput, error) { - if err := cfg.Validate(); err != nil { - return deployment.ChangesetOutput{}, err - } - - state, err := LoadOnchainState(e) - if err != nil { - return deployment.ChangesetOutput{}, err - } - // Generate proposal which enables new destination (from test router) on all source chains. - var batches []timelock.BatchChainOperation - for _, source := range cfg.SourceChainSelectors { - enableOnRampDest, err := state.Chains[source].OnRamp.ApplyDestChainConfigUpdates(deployment.SimTransactOpts(), []onramp.OnRampDestChainConfigArgs{ - { - DestChainSelector: cfg.NewChainSelector, - Router: state.Chains[source].TestRouter.Address(), - }, - }) - if err != nil { - return deployment.ChangesetOutput{}, err - } - enableFeeQuoterDest, err := state.Chains[source].FeeQuoter.ApplyDestChainConfigUpdates( - deployment.SimTransactOpts(), - []fee_quoter.FeeQuoterDestChainConfigArgs{ - { - DestChainSelector: cfg.NewChainSelector, - DestChainConfig: DefaultFeeQuoterDestChainConfig(), - }, - }) - if err != nil { - return deployment.ChangesetOutput{}, err - } - batches = append(batches, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(source), - Batch: []mcms.Operation{ - { - // Enable the source in on ramp - To: state.Chains[source].OnRamp.Address(), - Data: enableOnRampDest.Data(), - Value: big.NewInt(0), - }, - { - To: state.Chains[source].FeeQuoter.Address(), - Data: enableFeeQuoterDest.Data(), - Value: big.NewInt(0), - }, - }, - }) - } - - addChainOp, err := applyChainConfigUpdatesOp(e, state, cfg.HomeChainSelector, []uint64{cfg.NewChainSelector}) - if err != nil { - return deployment.ChangesetOutput{}, err - } - - batches = append(batches, timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(cfg.HomeChainSelector), - Batch: []mcms.Operation{ - addChainOp, - }, - }) - - var ( - timelocksPerChain = make(map[uint64]common.Address) - proposerMCMSes = make(map[uint64]*gethwrappers.ManyChainMultiSig) - ) - for _, chain := range append(cfg.SourceChainSelectors, cfg.HomeChainSelector) { - timelocksPerChain[chain] = state.Chains[chain].Timelock.Address() - proposerMCMSes[chain] = state.Chains[chain].ProposerMcm - } - prop, err := proposalutils.BuildProposalFromBatches( - timelocksPerChain, - proposerMCMSes, - batches, - "proposal to set new chains", - 0, - ) - if err != nil { - return deployment.ChangesetOutput{}, err - } - - return deployment.ChangesetOutput{ - Proposals: []timelock.MCMSWithTimelockProposal{*prop}, - }, nil -} - -func applyChainConfigUpdatesOp( - e deployment.Environment, - state CCIPOnChainState, - homeChainSel uint64, - chains []uint64, -) (mcms.Operation, error) { - nodes, err := deployment.NodeInfo(e.NodeIDs, e.Offchain) - if err != nil { - return mcms.Operation{}, err - } - encodedExtraChainConfig, err := chainconfig.EncodeChainConfig(chainconfig.ChainConfig{ - GasPriceDeviationPPB: ccipocr3.NewBigIntFromInt64(1000), - DAGasPriceDeviationPPB: ccipocr3.NewBigIntFromInt64(0), - OptimisticConfirmations: 1, - }) - if err != nil { - return mcms.Operation{}, err - } - var chainConfigUpdates []ccip_home.CCIPHomeChainConfigArgs - for _, chainSel := range chains { - chainConfig := setupConfigInfo(chainSel, nodes.NonBootstraps().PeerIDs(), - nodes.DefaultF(), encodedExtraChainConfig) - chainConfigUpdates = append(chainConfigUpdates, chainConfig) - } - - addChain, err := state.Chains[homeChainSel].CCIPHome.ApplyChainConfigUpdates( - deployment.SimTransactOpts(), - nil, - chainConfigUpdates, - ) - if err != nil { - return mcms.Operation{}, err - } - return mcms.Operation{ - To: state.Chains[homeChainSel].CCIPHome.Address(), - Data: addChain.Data(), - Value: big.NewInt(0), - }, nil -} diff --git a/deployment/ccip/changeset/cs_add_chain_test.go b/deployment/ccip/changeset/cs_add_chain_test.go deleted file mode 100644 index a70ea814881..00000000000 --- a/deployment/ccip/changeset/cs_add_chain_test.go +++ /dev/null @@ -1,335 +0,0 @@ -package changeset - -import ( - "testing" - "time" - - "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" - commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" - "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" - commontypes "github.com/smartcontractkit/chainlink/deployment/common/types" - "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" - - "github.com/ethereum/go-ethereum/common" - - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_home" - - "github.com/stretchr/testify/assert" - "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" - - "github.com/smartcontractkit/chainlink/deployment" - - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" - "github.com/smartcontractkit/chainlink/v2/core/logger" -) - -func TestAddChainInbound(t *testing.T) { - t.Skipf("Skipping test as it is running into timeout issues, move the test into integration in-memory tests") - t.Parallel() - // 4 chains where the 4th is added after initial deployment. - e := NewMemoryEnvironment(t, - WithChains(4), - WithJobsOnly(), - ) - state, err := LoadOnchainState(e.Env) - require.NoError(t, err) - // Take first non-home chain as the new chain. - newChain := e.Env.AllChainSelectorsExcluding([]uint64{e.HomeChainSel})[0] - // We deploy to the rest. - initialDeploy := e.Env.AllChainSelectorsExcluding([]uint64{newChain}) - newAddresses := deployment.NewMemoryAddressBook() - err = deployPrerequisiteChainContracts(e.Env, newAddresses, initialDeploy, nil) - require.NoError(t, err) - require.NoError(t, e.Env.ExistingAddresses.Merge(newAddresses)) - - cfg := proposalutils.SingleGroupTimelockConfig(t) - e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, nil, []commonchangeset.ChangesetApplication{ - { - Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployLinkToken), - Config: initialDeploy, - }, - { - Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployMCMSWithTimelock), - Config: map[uint64]commontypes.MCMSWithTimelockConfig{ - initialDeploy[0]: cfg, - initialDeploy[1]: cfg, - initialDeploy[2]: cfg, - }, - }, - }) - require.NoError(t, err) - newAddresses = deployment.NewMemoryAddressBook() - tokenConfig := NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds) - - chainConfig := make(map[uint64]CCIPOCRParams) - for _, chain := range initialDeploy { - chainConfig[chain] = DefaultOCRParams(e.FeedChainSel, nil, nil) - } - newChainCfg := NewChainsConfig{ - HomeChainSel: e.HomeChainSel, - FeedChainSel: e.FeedChainSel, - ChainConfigByChain: chainConfig, - } - e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, nil, []commonchangeset.ChangesetApplication{ - { - Changeset: commonchangeset.WrapChangeSet(DeployChainContracts), - Config: DeployChainContractsConfig{ - ChainSelectors: newChainCfg.Chains(), - HomeChainSelector: newChainCfg.HomeChainSel, - }, - }, - { - Changeset: commonchangeset.WrapChangeSet(ConfigureNewChains), - Config: newChainCfg, - }, - }) - require.NoError(t, err) - - state, err = LoadOnchainState(e.Env) - require.NoError(t, err) - - // Connect all the existing lanes. - for _, source := range initialDeploy { - for _, dest := range initialDeploy { - if source != dest { - require.NoError(t, AddLaneWithDefaultPricesAndFeeQuoterConfig(e.Env, state, source, dest, false)) - } - } - } - - rmnHomeAddress, err := deployment.SearchAddressBook(e.Env.ExistingAddresses, e.HomeChainSel, RMNHome) - require.NoError(t, err) - require.True(t, common.IsHexAddress(rmnHomeAddress)) - rmnHome, err := rmn_home.NewRMNHome(common.HexToAddress(rmnHomeAddress), e.Env.Chains[e.HomeChainSel].Client) - require.NoError(t, err) - - // Deploy contracts to new chain - e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, nil, []commonchangeset.ChangesetApplication{ - { - Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployLinkToken), - Config: []uint64{newChain}, - }, - { - Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployMCMSWithTimelock), - Config: map[uint64]commontypes.MCMSWithTimelockConfig{ - newChain: cfg, - }, - }, - }) - require.NoError(t, err) - newAddresses = deployment.NewMemoryAddressBook() - - err = deployPrerequisiteChainContracts(e.Env, newAddresses, []uint64{newChain}, nil) - require.NoError(t, err) - require.NoError(t, e.Env.ExistingAddresses.Merge(newAddresses)) - newAddresses = deployment.NewMemoryAddressBook() - err = deployChainContracts(e.Env, - e.Env.Chains[newChain], newAddresses, rmnHome) - require.NoError(t, err) - require.NoError(t, e.Env.ExistingAddresses.Merge(newAddresses)) - state, err = LoadOnchainState(e.Env) - require.NoError(t, err) - - // configure the testrouter appropriately on each chain - for _, source := range initialDeploy { - tx, err := state.Chains[source].TestRouter.ApplyRampUpdates(e.Env.Chains[source].DeployerKey, []router.RouterOnRamp{ - { - DestChainSelector: newChain, - OnRamp: state.Chains[source].OnRamp.Address(), - }, - }, nil, nil) - _, err = deployment.ConfirmIfNoError(e.Env.Chains[source], tx, err) - require.NoError(t, err) - } - - // transfer ownership to timelock - _, err = commonchangeset.ApplyChangesets(t, e.Env, map[uint64]*proposalutils.TimelockExecutionContracts{ - initialDeploy[0]: { - Timelock: state.Chains[initialDeploy[0]].Timelock, - CallProxy: state.Chains[initialDeploy[0]].CallProxy, - }, - initialDeploy[1]: { - Timelock: state.Chains[initialDeploy[1]].Timelock, - CallProxy: state.Chains[initialDeploy[1]].CallProxy, - }, - initialDeploy[2]: { - Timelock: state.Chains[initialDeploy[2]].Timelock, - CallProxy: state.Chains[initialDeploy[2]].CallProxy, - }, - }, []commonchangeset.ChangesetApplication{ - { - Changeset: commonchangeset.WrapChangeSet(commonchangeset.TransferToMCMSWithTimelock), - Config: genTestTransferOwnershipConfig(e, initialDeploy, state), - }, - { - Changeset: commonchangeset.WrapChangeSet(NewChainInboundChangeset), - Config: ChainInboundChangesetConfig{ - HomeChainSelector: e.HomeChainSel, - NewChainSelector: newChain, - SourceChainSelectors: initialDeploy, - }, - }, - }) - require.NoError(t, err) - - assertTimelockOwnership(t, e, initialDeploy, state) - - // TODO This currently is not working - Able to send the request here but request gets stuck in execution - // Send a new message and expect that this is delivered once the chain is completely set up as inbound - //TestSendRequest(t, e.Env, state, initialDeploy[0], newChain, true) - - _, err = commonchangeset.ApplyChangesets(t, e.Env, map[uint64]*proposalutils.TimelockExecutionContracts{ - e.HomeChainSel: { - Timelock: state.Chains[e.HomeChainSel].Timelock, - CallProxy: state.Chains[e.HomeChainSel].CallProxy, - }, - newChain: { - Timelock: state.Chains[newChain].Timelock, - CallProxy: state.Chains[newChain].CallProxy, - }, - }, []commonchangeset.ChangesetApplication{ - { - Changeset: commonchangeset.WrapChangeSet(AddDonAndSetCandidateChangeset), - Config: AddDonAndSetCandidateChangesetConfig{ - SetCandidateConfigBase: SetCandidateConfigBase{ - HomeChainSelector: e.HomeChainSel, - FeedChainSelector: e.FeedChainSel, - DONChainSelector: newChain, - PluginType: types.PluginTypeCCIPCommit, - CCIPOCRParams: DefaultOCRParams( - e.FeedChainSel, - tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[newChain].LinkToken, state.Chains[newChain].Weth9), - nil, - ), - MCMS: &MCMSConfig{ - MinDelay: 0, - }, - }, - }, - }, - { - Changeset: commonchangeset.WrapChangeSet(SetCandidateChangeset), - Config: SetCandidateChangesetConfig{ - SetCandidateConfigBase: SetCandidateConfigBase{ - HomeChainSelector: e.HomeChainSel, - FeedChainSelector: e.FeedChainSel, - DONChainSelector: newChain, - PluginType: types.PluginTypeCCIPExec, - CCIPOCRParams: DefaultOCRParams( - e.FeedChainSel, - tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[newChain].LinkToken, state.Chains[newChain].Weth9), - nil, - ), - MCMS: &MCMSConfig{ - MinDelay: 0, - }, - }, - }, - }, - { - Changeset: commonchangeset.WrapChangeSet(PromoteAllCandidatesChangeset), - Config: PromoteAllCandidatesChangesetConfig{ - HomeChainSelector: e.HomeChainSel, - DONChainSelector: newChain, - MCMS: &MCMSConfig{ - MinDelay: 0, - }, - }, - }, - }) - require.NoError(t, err) - - // verify if the configs are updated - require.NoError(t, ValidateCCIPHomeConfigSetUp( - e.Env.Logger, - state.Chains[e.HomeChainSel].CapabilityRegistry, - state.Chains[e.HomeChainSel].CCIPHome, - newChain, - )) - replayBlocks, err := LatestBlocksByChain(testcontext.Get(t), e.Env.Chains) - require.NoError(t, err) - - // Now configure the new chain using deployer key (not transferred to timelock yet). - var offRampEnables []offramp.OffRampSourceChainConfigArgs - for _, source := range initialDeploy { - offRampEnables = append(offRampEnables, offramp.OffRampSourceChainConfigArgs{ - Router: state.Chains[newChain].Router.Address(), - SourceChainSelector: source, - IsEnabled: true, - OnRamp: common.LeftPadBytes(state.Chains[source].OnRamp.Address().Bytes(), 32), - }) - } - tx, err := state.Chains[newChain].OffRamp.ApplySourceChainConfigUpdates(e.Env.Chains[newChain].DeployerKey, offRampEnables) - require.NoError(t, err) - _, err = deployment.ConfirmIfNoError(e.Env.Chains[newChain], tx, err) - require.NoError(t, err) - // Set the OCR3 config on new 4th chain to enable the plugin. - latestDON, err := internal.LatestCCIPDON(state.Chains[e.HomeChainSel].CapabilityRegistry) - require.NoError(t, err) - ocrConfigs, err := internal.BuildSetOCR3ConfigArgs(latestDON.Id, state.Chains[e.HomeChainSel].CCIPHome, newChain) - require.NoError(t, err) - tx, err = state.Chains[newChain].OffRamp.SetOCR3Configs(e.Env.Chains[newChain].DeployerKey, ocrConfigs) - require.NoError(t, err) - _, err = deployment.ConfirmIfNoError(e.Env.Chains[newChain], tx, err) - require.NoError(t, err) - - // Assert the inbound lanes to the new chain are wired correctly. - state, err = LoadOnchainState(e.Env) - require.NoError(t, err) - for _, chain := range initialDeploy { - cfg, err2 := state.Chains[chain].OnRamp.GetDestChainConfig(nil, newChain) - require.NoError(t, err2) - assert.Equal(t, cfg.Router, state.Chains[chain].TestRouter.Address()) - fqCfg, err2 := state.Chains[chain].FeeQuoter.GetDestChainConfig(nil, newChain) - require.NoError(t, err2) - assert.True(t, fqCfg.IsEnabled) - s, err2 := state.Chains[newChain].OffRamp.GetSourceChainConfig(nil, chain) - require.NoError(t, err2) - assert.Equal(t, common.LeftPadBytes(state.Chains[chain].OnRamp.Address().Bytes(), 32), s.OnRamp) - } - // Ensure job related logs are up to date. - time.Sleep(30 * time.Second) - ReplayLogs(t, e.Env.Offchain, replayBlocks) - - // TODO: Send via all inbound lanes and use parallel helper - // Now that the proposal has been executed we expect to be able to send traffic to this new 4th chain. - latesthdr, err := e.Env.Chains[newChain].Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - startBlock := latesthdr.Number.Uint64() - msgSentEvent := TestSendRequest(t, e.Env, state, initialDeploy[0], newChain, true, router.ClientEVM2AnyMessage{ - Receiver: common.LeftPadBytes(state.Chains[newChain].Receiver.Address().Bytes(), 32), - Data: []byte("hello world"), - TokenAmounts: nil, - FeeToken: common.HexToAddress("0x0"), - ExtraArgs: nil, - }) - require.NoError(t, - commonutils.JustError(ConfirmCommitWithExpectedSeqNumRange(t, e.Env.Chains[initialDeploy[0]], e.Env.Chains[newChain], state.Chains[newChain].OffRamp, &startBlock, cciptypes.SeqNumRange{ - cciptypes.SeqNum(1), - cciptypes.SeqNum(msgSentEvent.SequenceNumber), - }, true))) - require.NoError(t, - commonutils.JustError( - ConfirmExecWithSeqNrs( - t, - e.Env.Chains[initialDeploy[0]], - e.Env.Chains[newChain], - state.Chains[newChain].OffRamp, - &startBlock, - []uint64{msgSentEvent.SequenceNumber}, - ), - ), - ) - - linkAddress := state.Chains[newChain].LinkToken.Address() - feeQuoter := state.Chains[newChain].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, MockLinkPrice, timestampedPrice.Value) -} diff --git a/deployment/ccip/changeset/cs_ccip_home.go b/deployment/ccip/changeset/cs_ccip_home.go index f1e860d9d28..1d8c6782b76 100644 --- a/deployment/ccip/changeset/cs_ccip_home.go +++ b/deployment/ccip/changeset/cs_ccip_home.go @@ -1,9 +1,12 @@ package changeset import ( - "context" + "bytes" + "encoding/hex" "fmt" "math/big" + "os" + "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -11,9 +14,17 @@ import ( "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "github.com/smartcontractkit/chainlink-ccip/chainconfig" + "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink-ccip/pluginconfig" + "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/merklemulti" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" + commoncs "github.com/smartcontractkit/chainlink/deployment/common/changeset" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" + commontypes "github.com/smartcontractkit/chainlink/deployment/common/types" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_home" @@ -25,14 +36,82 @@ var ( _ deployment.ChangeSet[PromoteAllCandidatesChangesetConfig] = PromoteAllCandidatesChangeset _ deployment.ChangeSet[SetCandidateChangesetConfig] = SetCandidateChangeset _ deployment.ChangeSet[RevokeCandidateChangesetConfig] = RevokeCandidateChangeset + _ deployment.ChangeSet[UpdateChainConfigConfig] = UpdateChainConfig ) +type CCIPOCRParams struct { + OCRParameters commontypes.OCRParameters + // Note contains pointers to Arb feeds for prices + CommitOffChainConfig pluginconfig.CommitOffchainConfig + // Note ontains USDC config + ExecuteOffChainConfig pluginconfig.ExecuteOffchainConfig +} + +func (c CCIPOCRParams) Validate() error { + if err := c.OCRParameters.Validate(); err != nil { + return fmt.Errorf("invalid OCR parameters: %w", err) + } + if err := c.CommitOffChainConfig.Validate(); err != nil { + return fmt.Errorf("invalid commit off-chain config: %w", err) + } + if err := c.ExecuteOffChainConfig.Validate(); err != nil { + return fmt.Errorf("invalid execute off-chain config: %w", err) + } + return nil +} + +// DefaultOCRParams returns the default OCR parameters for a chain, +// except for a few values which must be parameterized (passed as arguments). +func DefaultOCRParams( + feedChainSel uint64, + tokenInfo map[ccipocr3.UnknownEncodedAddress]pluginconfig.TokenInfo, + tokenDataObservers []pluginconfig.TokenDataObserverConfig, +) CCIPOCRParams { + return CCIPOCRParams{ + OCRParameters: commontypes.OCRParameters{ + DeltaProgress: internal.DeltaProgress, + DeltaResend: internal.DeltaResend, + DeltaInitial: internal.DeltaInitial, + DeltaRound: internal.DeltaRound, + DeltaGrace: internal.DeltaGrace, + DeltaCertifiedCommitRequest: internal.DeltaCertifiedCommitRequest, + DeltaStage: internal.DeltaStage, + Rmax: internal.Rmax, + MaxDurationQuery: internal.MaxDurationQuery, + MaxDurationObservation: internal.MaxDurationObservation, + MaxDurationShouldAcceptAttestedReport: internal.MaxDurationShouldAcceptAttestedReport, + MaxDurationShouldTransmitAcceptedReport: internal.MaxDurationShouldTransmitAcceptedReport, + }, + ExecuteOffChainConfig: pluginconfig.ExecuteOffchainConfig{ + BatchGasLimit: internal.BatchGasLimit, + RelativeBoostPerWaitHour: internal.RelativeBoostPerWaitHour, + InflightCacheExpiry: *config.MustNewDuration(internal.InflightCacheExpiry), + RootSnoozeTime: *config.MustNewDuration(internal.RootSnoozeTime), + MessageVisibilityInterval: *config.MustNewDuration(internal.FirstBlockAge), + BatchingStrategyID: internal.BatchingStrategyID, + TokenDataObservers: tokenDataObservers, + }, + CommitOffChainConfig: pluginconfig.CommitOffchainConfig{ + RemoteGasPriceBatchWriteFrequency: *config.MustNewDuration(internal.RemoteGasPriceBatchWriteFrequency), + TokenPriceBatchWriteFrequency: *config.MustNewDuration(internal.TokenPriceBatchWriteFrequency), + TokenInfo: tokenInfo, + PriceFeedChainSelector: ccipocr3.ChainSelector(feedChainSel), + NewMsgScanBatchSize: merklemulti.MaxNumberTreeLeaves, + MaxReportTransmissionCheckAttempts: 5, + RMNEnabled: os.Getenv("ENABLE_RMN") == "true", // only enabled in manual test + RMNSignaturesTimeout: 30 * time.Minute, + MaxMerkleTreeSize: merklemulti.MaxNumberTreeLeaves, + SignObservationPrefix: "chainlink ccip 1.6 rmn observation", + }, + } +} + type PromoteAllCandidatesChangesetConfig struct { HomeChainSelector uint64 - // DONChainSelector is the chain selector of the DON that we want to promote the candidate config of. + // RemoteChainSelectors is the chain selector of the DONs that we want to promote the candidate config of. // Note that each (chain, ccip capability version) pair has a unique DON ID. - DONChainSelector uint64 + RemoteChainSelectors []uint64 // MCMS is optional MCMS configuration, if provided the changeset will generate an MCMS proposal. // If nil, the changeset will execute the commands directly using the deployer key @@ -40,65 +119,84 @@ type PromoteAllCandidatesChangesetConfig struct { MCMS *MCMSConfig } -func (p PromoteAllCandidatesChangesetConfig) Validate(e deployment.Environment, state CCIPOnChainState) (donID uint32, err error) { - if err := deployment.IsValidChainSelector(p.HomeChainSelector); err != nil { - return 0, fmt.Errorf("home chain selector invalid: %w", err) - } - if err := deployment.IsValidChainSelector(p.DONChainSelector); err != nil { - return 0, fmt.Errorf("don chain selector invalid: %w", err) +func (p PromoteAllCandidatesChangesetConfig) Validate(e deployment.Environment) ([]uint32, error) { + state, err := LoadOnchainState(e) + if err != nil { + return nil, err } - if len(e.NodeIDs) == 0 { - return 0, fmt.Errorf("NodeIDs must be set") + if err := deployment.IsValidChainSelector(p.HomeChainSelector); err != nil { + return nil, fmt.Errorf("home chain selector invalid: %w", err) } - if state.Chains[p.HomeChainSelector].CCIPHome == nil { - return 0, fmt.Errorf("CCIPHome contract does not exist") + homeChainState, exists := state.Chains[p.HomeChainSelector] + if !exists { + return nil, fmt.Errorf("home chain %d does not exist", p.HomeChainSelector) } - if state.Chains[p.HomeChainSelector].CapabilityRegistry == nil { - return 0, fmt.Errorf("CapabilityRegistry contract does not exist") - } - if state.Chains[p.DONChainSelector].OffRamp == nil { - // should not be possible, but a defensive check. - return 0, fmt.Errorf("OffRamp contract does not exist") + if err := commoncs.ValidateOwnership(e.GetContext(), p.MCMS != nil, e.Chains[p.HomeChainSelector].DeployerKey.From, homeChainState.Timelock.Address(), homeChainState.CapabilityRegistry); err != nil { + return nil, err } - donID, err = internal.DonIDForChain( - state.Chains[p.HomeChainSelector].CapabilityRegistry, - state.Chains[p.HomeChainSelector].CCIPHome, - p.DONChainSelector, - ) - if err != nil { - return 0, fmt.Errorf("fetch don id for chain: %w", err) - } - if donID == 0 { - return 0, fmt.Errorf("don doesn't exist in CR for chain %d", p.DONChainSelector) - } + var donIDs []uint32 + for _, chainSelector := range p.RemoteChainSelectors { + if err := deployment.IsValidChainSelector(chainSelector); err != nil { + return nil, fmt.Errorf("don chain selector invalid: %w", err) + } + chainState, exists := state.Chains[chainSelector] + if !exists { + return nil, fmt.Errorf("chain %d does not exist", chainSelector) + } + if chainState.OffRamp == nil { + // should not be possible, but a defensive check. + return nil, fmt.Errorf("OffRamp contract does not exist") + } - // Check that candidate digest and active digest are not both zero - this is enforced onchain. - commitConfigs, err := state.Chains[p.HomeChainSelector].CCIPHome.GetAllConfigs(&bind.CallOpts{ - Context: context.Background(), - }, donID, uint8(cctypes.PluginTypeCCIPCommit)) - if err != nil { - return 0, fmt.Errorf("fetching commit configs from cciphome: %w", err) - } + donID, err := internal.DonIDForChain( + state.Chains[p.HomeChainSelector].CapabilityRegistry, + state.Chains[p.HomeChainSelector].CCIPHome, + chainSelector, + ) + if err != nil { + return nil, fmt.Errorf("fetch don id for chain: %w", err) + } + if donID == 0 { + return nil, fmt.Errorf("don doesn't exist in CR for chain %d", p.RemoteChainSelectors) + } + // Check that candidate digest and active digest are not both zero - this is enforced onchain. + commitConfigs, err := state.Chains[p.HomeChainSelector].CCIPHome.GetAllConfigs(&bind.CallOpts{ + Context: e.GetContext(), + }, donID, uint8(cctypes.PluginTypeCCIPCommit)) + if err != nil { + return nil, fmt.Errorf("fetching commit configs from cciphome: %w", err) + } - execConfigs, err := state.Chains[p.HomeChainSelector].CCIPHome.GetAllConfigs(&bind.CallOpts{ - Context: context.Background(), - }, donID, uint8(cctypes.PluginTypeCCIPExec)) - if err != nil { - return 0, fmt.Errorf("fetching exec configs from cciphome: %w", err) - } + execConfigs, err := state.Chains[p.HomeChainSelector].CCIPHome.GetAllConfigs(&bind.CallOpts{ + Context: e.GetContext(), + }, donID, uint8(cctypes.PluginTypeCCIPExec)) + if err != nil { + return nil, fmt.Errorf("fetching exec configs from cciphome: %w", err) + } - if commitConfigs.ActiveConfig.ConfigDigest == [32]byte{} && - commitConfigs.CandidateConfig.ConfigDigest == [32]byte{} { - return 0, fmt.Errorf("commit active and candidate config digests are both zero") - } + if commitConfigs.ActiveConfig.ConfigDigest == [32]byte{} && + commitConfigs.CandidateConfig.ConfigDigest == [32]byte{} { + return nil, fmt.Errorf("commit active and candidate config digests are both zero") + } - if execConfigs.ActiveConfig.ConfigDigest == [32]byte{} && - execConfigs.CandidateConfig.ConfigDigest == [32]byte{} { - return 0, fmt.Errorf("exec active and candidate config digests are both zero") + if execConfigs.ActiveConfig.ConfigDigest == [32]byte{} && + execConfigs.CandidateConfig.ConfigDigest == [32]byte{} { + return nil, fmt.Errorf("exec active and candidate config digests are both zero") + } + donIDs = append(donIDs, donID) + } + if len(e.NodeIDs) == 0 { + return nil, fmt.Errorf("NodeIDs must be set") + } + if state.Chains[p.HomeChainSelector].CCIPHome == nil { + return nil, fmt.Errorf("CCIPHome contract does not exist") + } + if state.Chains[p.HomeChainSelector].CapabilityRegistry == nil { + return nil, fmt.Errorf("CapabilityRegistry contract does not exist") } - return donID, nil + return donIDs, nil } // PromoteAllCandidatesChangeset generates a proposal to call promoteCandidate on the CCIPHome through CapReg. @@ -110,14 +208,13 @@ func PromoteAllCandidatesChangeset( e deployment.Environment, cfg PromoteAllCandidatesChangesetConfig, ) (deployment.ChangesetOutput, error) { - state, err := LoadOnchainState(e) + donIDs, err := cfg.Validate(e) if err != nil { - return deployment.ChangesetOutput{}, err + return deployment.ChangesetOutput{}, fmt.Errorf("%w: %w", deployment.ErrInvalidConfig, err) } - - donID, err := cfg.Validate(e, state) + state, err := LoadOnchainState(e) if err != nil { - return deployment.ChangesetOutput{}, fmt.Errorf("%w: %w", deployment.ErrInvalidConfig, err) + return deployment.ChangesetOutput{}, err } nodes, err := deployment.NodeInfo(e.NodeIDs, e.Offchain) @@ -132,17 +229,21 @@ func PromoteAllCandidatesChangeset( homeChain := e.Chains[cfg.HomeChainSelector] - promoteCandidateOps, err := promoteAllCandidatesForChainOps( - txOpts, - homeChain, - state.Chains[cfg.HomeChainSelector].CapabilityRegistry, - state.Chains[cfg.HomeChainSelector].CCIPHome, - nodes.NonBootstraps(), - donID, - cfg.MCMS != nil, - ) - if err != nil { - return deployment.ChangesetOutput{}, fmt.Errorf("generating promote candidate ops: %w", err) + var ops []mcms.Operation + for _, donID := range donIDs { + promoteCandidateOps, err := promoteAllCandidatesForChainOps( + txOpts, + homeChain, + state.Chains[cfg.HomeChainSelector].CapabilityRegistry, + state.Chains[cfg.HomeChainSelector].CCIPHome, + nodes.NonBootstraps(), + donID, + cfg.MCMS != nil, + ) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("generating promote candidate ops: %w", err) + } + ops = append(ops, promoteCandidateOps...) } // Disabled MCMS means that we already executed the txes, so just return early w/out the proposals. @@ -159,7 +260,7 @@ func PromoteAllCandidatesChangeset( }, []timelock.BatchChainOperation{{ ChainIdentifier: mcms.ChainIdentifier(cfg.HomeChainSelector), - Batch: promoteCandidateOps, + Batch: ops, }}, "promoteCandidate for commit and execution", cfg.MCMS.MinDelay, @@ -181,12 +282,12 @@ type SetCandidateConfigBase struct { HomeChainSelector uint64 FeedChainSelector uint64 - // DONChainSelector is the chain selector of the chain where the DON will be added. - DONChainSelector uint64 + // OCRConfigPerRemoteChainSelector is the chain selector of the chain where the DON will be added. + OCRConfigPerRemoteChainSelector map[uint64]CCIPOCRParams + // Only set one plugin at a time. TODO + // come back and allow both. PluginType types.PluginType - // Note that the PluginType field is used to determine which field in CCIPOCRParams is used. - CCIPOCRParams CCIPOCRParams // MCMS is optional MCMS configuration, if provided the changeset will generate an MCMS proposal. // If nil, the changeset will execute the commands directly using the deployer key @@ -201,8 +302,46 @@ func (s SetCandidateConfigBase) Validate(e deployment.Environment, state CCIPOnC if err := deployment.IsValidChainSelector(s.FeedChainSelector); err != nil { return fmt.Errorf("feed chain selector invalid: %w", err) } - if err := deployment.IsValidChainSelector(s.DONChainSelector); err != nil { - return fmt.Errorf("don chain selector invalid: %w", err) + homeChainState, exists := state.Chains[s.HomeChainSelector] + if !exists { + return fmt.Errorf("home chain %d does not exist", s.HomeChainSelector) + } + if err := commoncs.ValidateOwnership(e.GetContext(), s.MCMS != nil, e.Chains[s.HomeChainSelector].DeployerKey.From, homeChainState.Timelock.Address(), homeChainState.CapabilityRegistry); err != nil { + return err + } + + for chainSelector, params := range s.OCRConfigPerRemoteChainSelector { + if err := deployment.IsValidChainSelector(chainSelector); err != nil { + return fmt.Errorf("don chain selector invalid: %w", err) + } + if state.Chains[chainSelector].OffRamp == nil { + // should not be possible, but a defensive check. + return fmt.Errorf("OffRamp contract does not exist on don chain selector %d", chainSelector) + } + if s.PluginType != types.PluginTypeCCIPCommit && + s.PluginType != types.PluginTypeCCIPExec { + return fmt.Errorf("PluginType must be set to either CCIPCommit or CCIPExec") + } + + // no donID check since this config is used for both adding a new DON and updating an existing one. + // see AddDonAndSetCandidateChangesetConfig.Validate and SetCandidateChangesetConfig.Validate + // for these checks. + // check that chain config is set up for the new chain + chainConfig, err := state.Chains[s.HomeChainSelector].CCIPHome.GetChainConfig(nil, chainSelector) + if err != nil { + return fmt.Errorf("get all chain configs: %w", err) + } + // FChain should never be zero if a chain config is set in CCIPHome + if chainConfig.FChain == 0 { + return fmt.Errorf("chain config not set up for new chain %d", chainSelector) + } + err = params.Validate() + if err != nil { + return fmt.Errorf("invalid ccip ocr params: %w", err) + } + + // TODO: validate token config in the commit config, if commit is the plugin. + // TODO: validate gas config in the chain config in cciphome for this RemoteChainSelectors. } if len(e.NodeIDs) == 0 { return fmt.Errorf("nodeIDs must be set") @@ -213,37 +352,6 @@ func (s SetCandidateConfigBase) Validate(e deployment.Environment, state CCIPOnC if state.Chains[s.HomeChainSelector].CapabilityRegistry == nil { return fmt.Errorf("CapabilityRegistry contract does not exist") } - if state.Chains[s.DONChainSelector].OffRamp == nil { - // should not be possible, but a defensive check. - return fmt.Errorf("OffRamp contract does not exist on don chain selector %d", s.DONChainSelector) - } - if s.PluginType != types.PluginTypeCCIPCommit && - s.PluginType != types.PluginTypeCCIPExec { - return fmt.Errorf("PluginType must be set to either CCIPCommit or CCIPExec") - } - - // no donID check since this config is used for both adding a new DON and updating an existing one. - // see AddDonAndSetCandidateChangesetConfig.Validate and SetCandidateChangesetConfig.Validate - // for these checks. - - // check that chain config is set up for the new chain - chainConfig, err := state.Chains[s.HomeChainSelector].CCIPHome.GetChainConfig(nil, s.DONChainSelector) - if err != nil { - return fmt.Errorf("get all chain configs: %w", err) - } - - // FChain should never be zero if a chain config is set in CCIPHome - if chainConfig.FChain == 0 { - return fmt.Errorf("chain config not set up for new chain %d", s.DONChainSelector) - } - - err = s.CCIPOCRParams.Validate() - if err != nil { - return fmt.Errorf("invalid ccip ocr params: %w", err) - } - - // TODO: validate token config in the commit config, if commit is the plugin. - // TODO: validate gas config in the chain config in cciphome for this DONChainSelector. if e.OCRSecrets.IsEmpty() { return fmt.Errorf("OCR secrets must be set") @@ -265,17 +373,19 @@ func (a AddDonAndSetCandidateChangesetConfig) Validate(e deployment.Environment, return err } - // check if a DON already exists for this chain - donID, err := internal.DonIDForChain( - state.Chains[a.HomeChainSelector].CapabilityRegistry, - state.Chains[a.HomeChainSelector].CCIPHome, - a.DONChainSelector, - ) - if err != nil { - return fmt.Errorf("fetch don id for chain: %w", err) - } - if donID != 0 { - return fmt.Errorf("don already exists in CR for chain %d, it has id %d", a.DONChainSelector, donID) + for chainSelector := range a.OCRConfigPerRemoteChainSelector { + // check if a DON already exists for this chain + donID, err := internal.DonIDForChain( + state.Chains[a.HomeChainSelector].CapabilityRegistry, + state.Chains[a.HomeChainSelector].CCIPHome, + chainSelector, + ) + if err != nil { + return fmt.Errorf("fetch don id for chain: %w", err) + } + if donID != 0 { + return fmt.Errorf("don already exists in CR for chain %d, it has id %d", chainSelector, donID) + } } return nil @@ -314,43 +424,46 @@ func AddDonAndSetCandidateChangeset( if cfg.MCMS != nil { txOpts = deployment.SimTransactOpts() } + var donOps []mcms.Operation + for chainSelector, params := range cfg.OCRConfigPerRemoteChainSelector { + newDONArgs, err := internal.BuildOCR3ConfigForCCIPHome( + e.OCRSecrets, + state.Chains[chainSelector].OffRamp, + e.Chains[chainSelector], + nodes.NonBootstraps(), + state.Chains[cfg.HomeChainSelector].RMNHome.Address(), + params.OCRParameters, + params.CommitOffChainConfig, + params.ExecuteOffChainConfig, + ) + if err != nil { + return deployment.ChangesetOutput{}, err + } - newDONArgs, err := internal.BuildOCR3ConfigForCCIPHome( - e.OCRSecrets, - state.Chains[cfg.DONChainSelector].OffRamp, - e.Chains[cfg.DONChainSelector], - nodes.NonBootstraps(), - state.Chains[cfg.HomeChainSelector].RMNHome.Address(), - cfg.CCIPOCRParams.OCRParameters, - cfg.CCIPOCRParams.CommitOffChainConfig, - cfg.CCIPOCRParams.ExecuteOffChainConfig, - ) - if err != nil { - return deployment.ChangesetOutput{}, err - } - - latestDon, err := internal.LatestCCIPDON(state.Chains[cfg.HomeChainSelector].CapabilityRegistry) - if err != nil { - return deployment.ChangesetOutput{}, err - } + latestDon, err := internal.LatestCCIPDON(state.Chains[cfg.HomeChainSelector].CapabilityRegistry) + if err != nil { + return deployment.ChangesetOutput{}, err + } - pluginOCR3Config, ok := newDONArgs[cfg.PluginType] - if !ok { - return deployment.ChangesetOutput{}, fmt.Errorf("missing commit plugin in ocr3Configs") - } + pluginOCR3Config, ok := newDONArgs[cfg.PluginType] + if !ok { + return deployment.ChangesetOutput{}, fmt.Errorf("missing commit plugin in ocr3Configs") + } - expectedDonID := latestDon.Id + 1 - addDonOp, err := newDonWithCandidateOp( - txOpts, - e.Chains[cfg.HomeChainSelector], - expectedDonID, - pluginOCR3Config, - state.Chains[cfg.HomeChainSelector].CapabilityRegistry, - nodes.NonBootstraps(), - cfg.MCMS != nil, - ) - if err != nil { - return deployment.ChangesetOutput{}, err + expectedDonID := latestDon.Id + 1 + addDonOp, err := newDonWithCandidateOp( + txOpts, + e.Chains[cfg.HomeChainSelector], + expectedDonID, + pluginOCR3Config, + state.Chains[cfg.HomeChainSelector].CapabilityRegistry, + nodes.NonBootstraps(), + cfg.MCMS != nil, + ) + if err != nil { + return deployment.ChangesetOutput{}, err + } + donOps = append(donOps, addDonOp) } if cfg.MCMS == nil { return deployment.ChangesetOutput{}, nil @@ -365,7 +478,7 @@ func AddDonAndSetCandidateChangeset( }, []timelock.BatchChainOperation{{ ChainIdentifier: mcms.ChainIdentifier(cfg.HomeChainSelector), - Batch: []mcms.Operation{addDonOp}, + Batch: donOps, }}, fmt.Sprintf("addDON on new Chain && setCandidate for plugin %s", cfg.PluginType.String()), cfg.MCMS.MinDelay, @@ -436,25 +549,29 @@ type SetCandidateChangesetConfig struct { SetCandidateConfigBase } -func (s SetCandidateChangesetConfig) Validate(e deployment.Environment, state CCIPOnChainState) (donID uint32, err error) { - err = s.SetCandidateConfigBase.Validate(e, state) +func (s SetCandidateChangesetConfig) Validate(e deployment.Environment, state CCIPOnChainState) (map[uint64]uint32, error) { + err := s.SetCandidateConfigBase.Validate(e, state) if err != nil { - return 0, err + return nil, err } - donID, err = internal.DonIDForChain( - state.Chains[s.HomeChainSelector].CapabilityRegistry, - state.Chains[s.HomeChainSelector].CCIPHome, - s.DONChainSelector, - ) - if err != nil { - return 0, fmt.Errorf("fetch don id for chain: %w", err) - } - if donID == 0 { - return 0, fmt.Errorf("don doesn't exist in CR for chain %d", s.DONChainSelector) + chainToDonIDs := make(map[uint64]uint32) + for chainSelector := range s.OCRConfigPerRemoteChainSelector { + donID, err := internal.DonIDForChain( + state.Chains[s.HomeChainSelector].CapabilityRegistry, + state.Chains[s.HomeChainSelector].CCIPHome, + chainSelector, + ) + if err != nil { + return nil, fmt.Errorf("fetch don id for chain: %w", err) + } + if donID == 0 { + return nil, fmt.Errorf("don doesn't exist in CR for chain %d", chainSelector) + } + chainToDonIDs[chainSelector] = donID } - return donID, nil + return chainToDonIDs, nil } // SetCandidateChangeset generates a proposal to call setCandidate on the CCIPHome through the capability registry. @@ -468,7 +585,7 @@ func SetCandidateChangeset( return deployment.ChangesetOutput{}, err } - donID, err := cfg.Validate(e, state) + chainToDonIDs, err := cfg.Validate(e, state) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("%w: %w", deployment.ErrInvalidConfig, err) } @@ -482,37 +599,40 @@ func SetCandidateChangeset( if cfg.MCMS != nil { txOpts = deployment.SimTransactOpts() } + var setCandidateOps []mcms.Operation + for chainSelector, params := range cfg.OCRConfigPerRemoteChainSelector { + newDONArgs, err := internal.BuildOCR3ConfigForCCIPHome( + e.OCRSecrets, + state.Chains[chainSelector].OffRamp, + e.Chains[chainSelector], + nodes.NonBootstraps(), + state.Chains[cfg.HomeChainSelector].RMNHome.Address(), + params.OCRParameters, + params.CommitOffChainConfig, + params.ExecuteOffChainConfig, + ) + if err != nil { + return deployment.ChangesetOutput{}, err + } - newDONArgs, err := internal.BuildOCR3ConfigForCCIPHome( - e.OCRSecrets, - state.Chains[cfg.DONChainSelector].OffRamp, - e.Chains[cfg.DONChainSelector], - nodes.NonBootstraps(), - state.Chains[cfg.HomeChainSelector].RMNHome.Address(), - cfg.CCIPOCRParams.OCRParameters, - cfg.CCIPOCRParams.CommitOffChainConfig, - cfg.CCIPOCRParams.ExecuteOffChainConfig, - ) - if err != nil { - return deployment.ChangesetOutput{}, err - } - - config, ok := newDONArgs[cfg.PluginType] - if !ok { - return deployment.ChangesetOutput{}, fmt.Errorf("missing %s plugin in ocr3Configs", cfg.PluginType.String()) - } + config, ok := newDONArgs[cfg.PluginType] + if !ok { + return deployment.ChangesetOutput{}, fmt.Errorf("missing %s plugin in ocr3Configs", cfg.PluginType.String()) + } - setCandidateMCMSOps, err := setCandidateOnExistingDon( - txOpts, - e.Chains[cfg.HomeChainSelector], - state.Chains[cfg.HomeChainSelector].CapabilityRegistry, - nodes.NonBootstraps(), - donID, - config, - cfg.MCMS != nil, - ) - if err != nil { - return deployment.ChangesetOutput{}, err + setCandidateMCMSOps, err := setCandidateOnExistingDon( + txOpts, + e.Chains[cfg.HomeChainSelector], + state.Chains[cfg.HomeChainSelector].CapabilityRegistry, + nodes.NonBootstraps(), + chainToDonIDs[chainSelector], + config, + cfg.MCMS != nil, + ) + if err != nil { + return deployment.ChangesetOutput{}, err + } + setCandidateOps = append(setCandidateOps, setCandidateMCMSOps...) } if cfg.MCMS == nil { @@ -528,7 +648,7 @@ func SetCandidateChangeset( }, []timelock.BatchChainOperation{{ ChainIdentifier: mcms.ChainIdentifier(cfg.HomeChainSelector), - Batch: setCandidateMCMSOps, + Batch: setCandidateOps, }}, fmt.Sprintf("SetCandidate for %s plugin", cfg.PluginType.String()), cfg.MCMS.MinDelay, @@ -714,9 +834,9 @@ func promoteAllCandidatesForChainOps( type RevokeCandidateChangesetConfig struct { HomeChainSelector uint64 - // DONChainSelector is the chain selector whose candidate config we want to revoke. - DONChainSelector uint64 - PluginType types.PluginType + // RemoteChainSelector is the chain selector whose candidate config we want to revoke. + RemoteChainSelector uint64 + PluginType types.PluginType // MCMS is optional MCMS configuration, if provided the changeset will generate an MCMS proposal. // If nil, the changeset will execute the commands directly using the deployer key @@ -728,7 +848,7 @@ func (r RevokeCandidateChangesetConfig) Validate(e deployment.Environment, state if err := deployment.IsValidChainSelector(r.HomeChainSelector); err != nil { return 0, fmt.Errorf("home chain selector invalid: %w", err) } - if err := deployment.IsValidChainSelector(r.DONChainSelector); err != nil { + if err := deployment.IsValidChainSelector(r.RemoteChainSelector); err != nil { return 0, fmt.Errorf("don chain selector invalid: %w", err) } if len(e.NodeIDs) == 0 { @@ -740,18 +860,25 @@ func (r RevokeCandidateChangesetConfig) Validate(e deployment.Environment, state if state.Chains[r.HomeChainSelector].CapabilityRegistry == nil { return 0, fmt.Errorf("CapabilityRegistry contract does not exist") } + homeChainState, exists := state.Chains[r.HomeChainSelector] + if !exists { + return 0, fmt.Errorf("home chain %d does not exist", r.HomeChainSelector) + } + if err := commoncs.ValidateOwnership(e.GetContext(), r.MCMS != nil, e.Chains[r.HomeChainSelector].DeployerKey.From, homeChainState.Timelock.Address(), homeChainState.CapabilityRegistry); err != nil { + return 0, err + } // check that the don exists for this chain donID, err = internal.DonIDForChain( state.Chains[r.HomeChainSelector].CapabilityRegistry, state.Chains[r.HomeChainSelector].CCIPHome, - r.DONChainSelector, + r.RemoteChainSelector, ) if err != nil { return 0, fmt.Errorf("fetch don id for chain: %w", err) } if donID == 0 { - return 0, fmt.Errorf("don doesn't exist in CR for chain %d", r.DONChainSelector) + return 0, fmt.Errorf("don doesn't exist in CR for chain %d", r.RemoteChainSelector) } // check that candidate digest is not zero - this is enforced onchain. @@ -816,7 +943,7 @@ func RevokeCandidateChangeset(e deployment.Environment, cfg RevokeCandidateChang ChainIdentifier: mcms.ChainIdentifier(cfg.HomeChainSelector), Batch: ops, }}, - fmt.Sprintf("revokeCandidate for don %d", cfg.DONChainSelector), + fmt.Sprintf("revokeCandidate for don %d", cfg.RemoteChainSelector), cfg.MCMS.MinDelay, ) if err != nil { @@ -888,3 +1015,219 @@ func revokeCandidateOps( Value: big.NewInt(0), }}, nil } + +type ChainConfig struct { + Readers [][32]byte + FChain uint8 + EncodableChainConfig chainconfig.ChainConfig +} + +type UpdateChainConfigConfig struct { + HomeChainSelector uint64 + RemoteChainRemoves []uint64 + RemoteChainAdds map[uint64]ChainConfig + MCMS *MCMSConfig +} + +func (c UpdateChainConfigConfig) Validate(e deployment.Environment) error { + state, err := LoadOnchainState(e) + if err != nil { + return err + } + if err := deployment.IsValidChainSelector(c.HomeChainSelector); err != nil { + return fmt.Errorf("home chain selector invalid: %w", err) + } + if len(c.RemoteChainRemoves) == 0 && len(c.RemoteChainAdds) == 0 { + return fmt.Errorf("no chain adds or removes") + } + homeChainState, exists := state.Chains[c.HomeChainSelector] + if !exists { + return fmt.Errorf("home chain %d does not exist", c.HomeChainSelector) + } + if err := commoncs.ValidateOwnership(e.GetContext(), c.MCMS != nil, e.Chains[c.HomeChainSelector].DeployerKey.From, homeChainState.Timelock.Address(), homeChainState.CCIPHome); err != nil { + return err + } + for _, remove := range c.RemoteChainRemoves { + if err := deployment.IsValidChainSelector(remove); err != nil { + return fmt.Errorf("chain remove selector invalid: %w", err) + } + if _, ok := state.SupportedChains()[remove]; !ok { + return fmt.Errorf("chain to remove %d is not supported", remove) + } + } + for add, ccfg := range c.RemoteChainAdds { + if err := deployment.IsValidChainSelector(add); err != nil { + return fmt.Errorf("chain remove selector invalid: %w", err) + } + if _, ok := state.SupportedChains()[add]; !ok { + return fmt.Errorf("chain to add %d is not supported", add) + } + if ccfg.FChain == 0 { + return fmt.Errorf("FChain must be set") + } + if len(ccfg.Readers) == 0 { + return fmt.Errorf("Readers must be set") + } + } + return nil +} + +func UpdateChainConfig(e deployment.Environment, cfg UpdateChainConfigConfig) (deployment.ChangesetOutput, error) { + if err := cfg.Validate(e); err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("%w: %w", deployment.ErrInvalidConfig, err) + } + state, err := LoadOnchainState(e) + if err != nil { + return deployment.ChangesetOutput{}, err + } + txOpts := e.Chains[cfg.HomeChainSelector].DeployerKey + txOpts.Context = e.GetContext() + if cfg.MCMS != nil { + txOpts = deployment.SimTransactOpts() + } + var adds []ccip_home.CCIPHomeChainConfigArgs + for chain, ccfg := range cfg.RemoteChainAdds { + encodedChainConfig, err := chainconfig.EncodeChainConfig(chainconfig.ChainConfig{ + GasPriceDeviationPPB: ccfg.EncodableChainConfig.GasPriceDeviationPPB, + DAGasPriceDeviationPPB: ccfg.EncodableChainConfig.DAGasPriceDeviationPPB, + OptimisticConfirmations: ccfg.EncodableChainConfig.OptimisticConfirmations, + }) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("encoding chain config: %w", err) + } + chainConfig := ccip_home.CCIPHomeChainConfig{ + Readers: ccfg.Readers, + FChain: ccfg.FChain, + Config: encodedChainConfig, + } + existingCfg, err := state.Chains[cfg.HomeChainSelector].CCIPHome.GetChainConfig(nil, chain) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("get chain config for selector %d: %w", chain, err) + } + if isChainConfigEqual(existingCfg, chainConfig) { + e.Logger.Infow("Chain config already exists, not applying again", + "addedChain", chain, + "chainConfig", chainConfig, + ) + continue + } + adds = append(adds, ccip_home.CCIPHomeChainConfigArgs{ + ChainSelector: chain, + ChainConfig: chainConfig, + }) + } + + tx, err := state.Chains[cfg.HomeChainSelector].CCIPHome.ApplyChainConfigUpdates(txOpts, cfg.RemoteChainRemoves, adds) + if cfg.MCMS == nil { + _, err = deployment.ConfirmIfNoError(e.Chains[cfg.HomeChainSelector], tx, err) + if err != nil { + return deployment.ChangesetOutput{}, err + } + e.Logger.Infof("Updated chain config on chain %d removes %v, adds %v", cfg.HomeChainSelector, cfg.RemoteChainRemoves, cfg.RemoteChainAdds) + return deployment.ChangesetOutput{}, nil + } + + p, err := proposalutils.BuildProposalFromBatches( + map[uint64]common.Address{ + cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].Timelock.Address(), + }, + map[uint64]*gethwrappers.ManyChainMultiSig{ + cfg.HomeChainSelector: state.Chains[cfg.HomeChainSelector].ProposerMcm, + }, + []timelock.BatchChainOperation{{ + ChainIdentifier: mcms.ChainIdentifier(cfg.HomeChainSelector), + Batch: []mcms.Operation{ + { + To: state.Chains[cfg.HomeChainSelector].CCIPHome.Address(), + Data: tx.Data(), + Value: big.NewInt(0), + }, + }, + }}, + "Update chain config", + cfg.MCMS.MinDelay, + ) + if err != nil { + return deployment.ChangesetOutput{}, err + } + e.Logger.Infof("Proposed chain config update on chain %d removes %v, adds %v", cfg.HomeChainSelector, cfg.RemoteChainRemoves, cfg.RemoteChainAdds) + return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ + *p, + }}, nil +} + +func isChainConfigEqual(a, b ccip_home.CCIPHomeChainConfig) bool { + mapReader := make(map[[32]byte]struct{}) + for i := range a.Readers { + mapReader[a.Readers[i]] = struct{}{} + } + for i := range b.Readers { + if _, ok := mapReader[b.Readers[i]]; !ok { + return false + } + } + return bytes.Equal(a.Config, b.Config) && + a.FChain == b.FChain +} + +// ValidateCCIPHomeConfigSetUp checks that the commit and exec active and candidate configs are set up correctly +// TODO: Utilize this +func ValidateCCIPHomeConfigSetUp( + lggr logger.Logger, + capReg *capabilities_registry.CapabilitiesRegistry, + ccipHome *ccip_home.CCIPHome, + chainSel uint64, +) error { + // fetch DONID + donID, err := internal.DonIDForChain(capReg, ccipHome, chainSel) + if err != nil { + return fmt.Errorf("fetch don id for chain: %w", err) + } + if donID == 0 { + return fmt.Errorf("don id for chain (%d) does not exist", chainSel) + } + + // final sanity checks on configs. + commitConfigs, err := ccipHome.GetAllConfigs(&bind.CallOpts{ + //Pending: true, + }, donID, uint8(cctypes.PluginTypeCCIPCommit)) + if err != nil { + return fmt.Errorf("get all commit configs: %w", err) + } + commitActiveDigest, err := ccipHome.GetActiveDigest(nil, donID, uint8(cctypes.PluginTypeCCIPCommit)) + if err != nil { + return fmt.Errorf("get active commit digest: %w", err) + } + lggr.Debugw("Fetched active commit digest", "commitActiveDigest", hex.EncodeToString(commitActiveDigest[:])) + commitCandidateDigest, err := ccipHome.GetCandidateDigest(nil, donID, uint8(cctypes.PluginTypeCCIPCommit)) + if err != nil { + return fmt.Errorf("get commit candidate digest: %w", err) + } + lggr.Debugw("Fetched candidate commit digest", "commitCandidateDigest", hex.EncodeToString(commitCandidateDigest[:])) + if commitConfigs.ActiveConfig.ConfigDigest == [32]byte{} { + return fmt.Errorf( + "active config digest is empty for commit, expected nonempty, donID: %d, cfg: %+v, config digest from GetActiveDigest call: %x, config digest from GetCandidateDigest call: %x", + donID, commitConfigs.ActiveConfig, commitActiveDigest, commitCandidateDigest) + } + if commitConfigs.CandidateConfig.ConfigDigest != [32]byte{} { + return fmt.Errorf( + "candidate config digest is nonempty for commit, expected empty, donID: %d, cfg: %+v, config digest from GetCandidateDigest call: %x, config digest from GetActiveDigest call: %x", + donID, commitConfigs.CandidateConfig, commitCandidateDigest, commitActiveDigest) + } + + execConfigs, err := ccipHome.GetAllConfigs(nil, donID, uint8(cctypes.PluginTypeCCIPExec)) + if err != nil { + return fmt.Errorf("get all exec configs: %w", err) + } + lggr.Debugw("Fetched exec configs", + "ActiveConfig.ConfigDigest", hex.EncodeToString(execConfigs.ActiveConfig.ConfigDigest[:]), + "CandidateConfig.ConfigDigest", hex.EncodeToString(execConfigs.CandidateConfig.ConfigDigest[:]), + ) + if execConfigs.ActiveConfig.ConfigDigest == [32]byte{} { + return fmt.Errorf("active config digest is empty for exec, expected nonempty, cfg: %v", execConfigs.ActiveConfig) + } + if execConfigs.CandidateConfig.ConfigDigest != [32]byte{} { + return fmt.Errorf("candidate config digest is nonempty for exec, expected empty, cfg: %v", execConfigs.CandidateConfig) + } + return nil +} diff --git a/deployment/ccip/changeset/cs_ccip_home_test.go b/deployment/ccip/changeset/cs_ccip_home_test.go index b728e7b0c1d..b487f1acc26 100644 --- a/deployment/ccip/changeset/cs_ccip_home_test.go +++ b/deployment/ccip/changeset/cs_ccip_home_test.go @@ -1,11 +1,15 @@ package changeset import ( + "math/big" "testing" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/assert" "golang.org/x/exp/maps" + "github.com/smartcontractkit/chainlink-ccip/chainconfig" + cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" @@ -83,9 +87,9 @@ func Test_PromoteCandidate(t *testing.T) { { Changeset: commonchangeset.WrapChangeSet(PromoteAllCandidatesChangeset), Config: PromoteAllCandidatesChangesetConfig{ - HomeChainSelector: tenv.HomeChainSel, - DONChainSelector: dest, - MCMS: mcmsConfig, + HomeChainSelector: tenv.HomeChainSel, + RemoteChainSelectors: []uint64{dest}, + MCMS: mcmsConfig, }, }, }) @@ -176,14 +180,15 @@ func Test_SetCandidate(t *testing.T) { SetCandidateConfigBase: SetCandidateConfigBase{ HomeChainSelector: tenv.HomeChainSel, FeedChainSelector: tenv.FeedChainSel, - DONChainSelector: dest, - PluginType: types.PluginTypeCCIPCommit, - CCIPOCRParams: DefaultOCRParams( - tenv.FeedChainSel, - tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9), - nil, - ), - MCMS: mcmsConfig, + OCRConfigPerRemoteChainSelector: map[uint64]CCIPOCRParams{ + dest: DefaultOCRParams( + tenv.FeedChainSel, + tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9), + nil, + ), + }, + PluginType: types.PluginTypeCCIPCommit, + MCMS: mcmsConfig, }, }, }, @@ -193,14 +198,15 @@ func Test_SetCandidate(t *testing.T) { SetCandidateConfigBase: SetCandidateConfigBase{ HomeChainSelector: tenv.HomeChainSel, FeedChainSelector: tenv.FeedChainSel, - DONChainSelector: dest, - PluginType: types.PluginTypeCCIPExec, - CCIPOCRParams: DefaultOCRParams( - tenv.FeedChainSel, - tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9), - nil, - ), - MCMS: mcmsConfig, + OCRConfigPerRemoteChainSelector: map[uint64]CCIPOCRParams{ + dest: DefaultOCRParams( + tenv.FeedChainSel, + tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9), + nil, + ), + }, + PluginType: types.PluginTypeCCIPExec, + MCMS: mcmsConfig, }, }, }, @@ -295,14 +301,15 @@ func Test_RevokeCandidate(t *testing.T) { SetCandidateConfigBase: SetCandidateConfigBase{ HomeChainSelector: tenv.HomeChainSel, FeedChainSelector: tenv.FeedChainSel, - DONChainSelector: dest, - PluginType: types.PluginTypeCCIPCommit, - CCIPOCRParams: DefaultOCRParams( - tenv.FeedChainSel, - tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9), - nil, - ), - MCMS: mcmsConfig, + OCRConfigPerRemoteChainSelector: map[uint64]CCIPOCRParams{ + dest: DefaultOCRParams( + tenv.FeedChainSel, + tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9), + nil, + ), + }, + PluginType: types.PluginTypeCCIPCommit, + MCMS: mcmsConfig, }, }, }, @@ -312,14 +319,15 @@ func Test_RevokeCandidate(t *testing.T) { SetCandidateConfigBase: SetCandidateConfigBase{ HomeChainSelector: tenv.HomeChainSel, FeedChainSelector: tenv.FeedChainSel, - DONChainSelector: dest, - PluginType: types.PluginTypeCCIPExec, - CCIPOCRParams: DefaultOCRParams( - tenv.FeedChainSel, - tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9), - nil, - ), - MCMS: mcmsConfig, + OCRConfigPerRemoteChainSelector: map[uint64]CCIPOCRParams{ + dest: DefaultOCRParams( + tenv.FeedChainSel, + tokenConfig.GetTokenInfo(logger.TestLogger(t), state.Chains[dest].LinkToken, state.Chains[dest].Weth9), + nil, + ), + }, + PluginType: types.PluginTypeCCIPExec, + MCMS: mcmsConfig, }, }, }, @@ -352,19 +360,19 @@ func Test_RevokeCandidate(t *testing.T) { { Changeset: commonchangeset.WrapChangeSet(RevokeCandidateChangeset), Config: RevokeCandidateChangesetConfig{ - HomeChainSelector: tenv.HomeChainSel, - DONChainSelector: dest, - PluginType: types.PluginTypeCCIPCommit, - MCMS: mcmsConfig, + HomeChainSelector: tenv.HomeChainSel, + RemoteChainSelector: dest, + PluginType: types.PluginTypeCCIPCommit, + MCMS: mcmsConfig, }, }, { Changeset: commonchangeset.WrapChangeSet(RevokeCandidateChangeset), Config: RevokeCandidateChangesetConfig{ - HomeChainSelector: tenv.HomeChainSel, - DONChainSelector: dest, - PluginType: types.PluginTypeCCIPExec, - MCMS: mcmsConfig, + HomeChainSelector: tenv.HomeChainSel, + RemoteChainSelector: dest, + PluginType: types.PluginTypeCCIPExec, + MCMS: mcmsConfig, }, }, }) @@ -415,3 +423,104 @@ func transferToTimelock( require.NoError(t, err) assertTimelockOwnership(t, tenv, []uint64{source, dest}, state) } + +func Test_UpdateChainConfigs(t *testing.T) { + for _, tc := range []struct { + name string + mcmsEnabled bool + }{ + { + name: "MCMS enabled", + mcmsEnabled: true, + }, + { + name: "MCMS disabled", + mcmsEnabled: false, + }, + } { + t.Run(tc.name, func(t *testing.T) { + tenv := NewMemoryEnvironment(t, WithChains(3)) + state, err := LoadOnchainState(tenv.Env) + require.NoError(t, err) + + allChains := maps.Keys(tenv.Env.Chains) + source := allChains[0] + dest := allChains[1] + otherChain := allChains[2] + + if tc.mcmsEnabled { + // Transfer ownership to timelock so that we can promote the zero digest later down the line. + transferToTimelock(t, tenv, state, source, dest) + } + + ccipHome := state.Chains[tenv.HomeChainSel].CCIPHome + otherChainConfig, err := ccipHome.GetChainConfig(nil, otherChain) + require.NoError(t, err) + assert.True(t, otherChainConfig.FChain != 0) + + var mcmsConfig *MCMSConfig + if tc.mcmsEnabled { + mcmsConfig = &MCMSConfig{ + MinDelay: 0, + } + } + _, err = commonchangeset.ApplyChangesets(t, tenv.Env, map[uint64]*proposalutils.TimelockExecutionContracts{ + tenv.HomeChainSel: { + Timelock: state.Chains[tenv.HomeChainSel].Timelock, + CallProxy: state.Chains[tenv.HomeChainSel].CallProxy, + }, + }, []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(UpdateChainConfig), + Config: UpdateChainConfigConfig{ + HomeChainSelector: tenv.HomeChainSel, + RemoteChainRemoves: []uint64{otherChain}, + RemoteChainAdds: make(map[uint64]ChainConfig), + MCMS: mcmsConfig, + }, + }, + }) + require.NoError(t, err) + + // other chain should be gone + chainConfigAfter, err := ccipHome.GetChainConfig(nil, otherChain) + require.NoError(t, err) + assert.True(t, chainConfigAfter.FChain == 0) + + // Lets add it back now. + _, err = commonchangeset.ApplyChangesets(t, tenv.Env, map[uint64]*proposalutils.TimelockExecutionContracts{ + tenv.HomeChainSel: { + Timelock: state.Chains[tenv.HomeChainSel].Timelock, + CallProxy: state.Chains[tenv.HomeChainSel].CallProxy, + }, + }, []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(UpdateChainConfig), + Config: UpdateChainConfigConfig{ + HomeChainSelector: tenv.HomeChainSel, + RemoteChainRemoves: []uint64{}, + RemoteChainAdds: map[uint64]ChainConfig{ + otherChain: { + EncodableChainConfig: chainconfig.ChainConfig{ + GasPriceDeviationPPB: cciptypes.BigInt{Int: big.NewInt(internal.GasPriceDeviationPPB)}, + DAGasPriceDeviationPPB: cciptypes.BigInt{Int: big.NewInt(internal.DAGasPriceDeviationPPB)}, + OptimisticConfirmations: internal.OptimisticConfirmations, + }, + FChain: otherChainConfig.FChain, + Readers: otherChainConfig.Readers, + }, + }, + MCMS: mcmsConfig, + }, + }, + }) + require.NoError(t, err) + + chainConfigAfter2, err := ccipHome.GetChainConfig(nil, otherChain) + require.NoError(t, err) + assert.Equal(t, chainConfigAfter2.FChain, otherChainConfig.FChain) + assert.Equal(t, chainConfigAfter2.Readers, otherChainConfig.Readers) + assert.Equal(t, chainConfigAfter2.Config, otherChainConfig.Config) + }) + } +} diff --git a/deployment/ccip/changeset/cs_chain_contracts.go b/deployment/ccip/changeset/cs_chain_contracts.go new file mode 100644 index 00000000000..e97772793b0 --- /dev/null +++ b/deployment/ccip/changeset/cs_chain_contracts.go @@ -0,0 +1,757 @@ +package changeset + +import ( + "bytes" + "context" + "encoding/hex" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" + "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" + "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" + commoncs "github.com/smartcontractkit/chainlink/deployment/common/changeset" + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" + cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" +) + +var ( + _ deployment.ChangeSet[UpdateOnRampDestsConfig] = UpdateOnRampsDests + _ deployment.ChangeSet[UpdateOffRampSourcesConfig] = UpdateOffRampSources + _ deployment.ChangeSet[UpdateRouterRampsConfig] = UpdateRouterRamps + _ deployment.ChangeSet[UpdateFeeQuoterDestsConfig] = UpdateFeeQuoterDests + _ deployment.ChangeSet[SetOCR3OffRampConfig] = SetOCR3OffRamp +) + +type UpdateOnRampDestsConfig struct { + UpdatesByChain map[uint64]map[uint64]OnRampDestinationUpdate + // Disallow mixing MCMS/non-MCMS per chain for simplicity. + // (can still be acheived by calling this function multiple times) + MCMS *MCMSConfig +} + +type OnRampDestinationUpdate struct { + IsEnabled bool // If false, disables the destination by setting router to 0x0. + TestRouter bool // Flag for safety only allow specifying either router or testRouter. + AllowListEnabled bool +} + +func (cfg UpdateOnRampDestsConfig) Validate(e deployment.Environment) error { + state, err := LoadOnchainState(e) + if err != nil { + return err + } + supportedChains := state.SupportedChains() + for chainSel, updates := range cfg.UpdatesByChain { + chainState, ok := state.Chains[chainSel] + if !ok { + return fmt.Errorf("chain %d not found in onchain state", chainSel) + } + if chainState.TestRouter == nil { + return fmt.Errorf("missing test router for chain %d", chainSel) + } + if chainState.Router == nil { + return fmt.Errorf("missing router for chain %d", chainSel) + } + if chainState.OnRamp == nil { + return fmt.Errorf("missing onramp onramp for chain %d", chainSel) + } + if err := commoncs.ValidateOwnership(e.GetContext(), cfg.MCMS != nil, e.Chains[chainSel].DeployerKey.From, chainState.Timelock.Address(), chainState.OnRamp); err != nil { + return err + } + + for destination := range updates { + // Destination cannot be an unknown destination. + if _, ok := supportedChains[destination]; !ok { + return fmt.Errorf("destination chain %d is not a supported %s", destination, chainState.OnRamp.Address()) + } + sc, err := chainState.OnRamp.GetStaticConfig(&bind.CallOpts{Context: e.GetContext()}) + if err != nil { + return fmt.Errorf("failed to get onramp static config %s: %w", chainState.OnRamp.Address(), err) + } + if destination == sc.ChainSelector { + return fmt.Errorf("cannot update onramp destination to the same chain") + } + } + } + return nil +} + +// UpdateOnRampsDests updates the onramp destinations for each onramp +// in the chains specified. Multichain support is important - consider when we add a new chain +// and need to update the onramp destinations for all chains to support the new chain. +func UpdateOnRampsDests(e deployment.Environment, cfg UpdateOnRampDestsConfig) (deployment.ChangesetOutput, error) { + if err := cfg.Validate(e); err != nil { + return deployment.ChangesetOutput{}, err + } + s, err := LoadOnchainState(e) + if err != nil { + return deployment.ChangesetOutput{}, err + } + var batches []timelock.BatchChainOperation + timelocks := make(map[uint64]common.Address) + proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + for chainSel, updates := range cfg.UpdatesByChain { + txOpts := e.Chains[chainSel].DeployerKey + txOpts.Context = e.GetContext() + if cfg.MCMS != nil { + txOpts = deployment.SimTransactOpts() + } + onRamp := s.Chains[chainSel].OnRamp + var args []onramp.OnRampDestChainConfigArgs + for destination, update := range updates { + router := common.HexToAddress("0x0") + // If not enabled, set router to 0x0. + if update.IsEnabled { + if update.TestRouter { + router = s.Chains[chainSel].TestRouter.Address() + } else { + router = s.Chains[chainSel].Router.Address() + } + } + args = append(args, onramp.OnRampDestChainConfigArgs{ + DestChainSelector: destination, + Router: router, + AllowlistEnabled: update.AllowListEnabled, + }) + } + tx, err := onRamp.ApplyDestChainConfigUpdates(txOpts, args) + if err != nil { + return deployment.ChangesetOutput{}, err + } + if cfg.MCMS == nil { + if _, err := deployment.ConfirmIfNoError(e.Chains[chainSel], tx, err); err != nil { + return deployment.ChangesetOutput{}, err + } + } else { + batches = append(batches, timelock.BatchChainOperation{ + ChainIdentifier: mcms.ChainIdentifier(chainSel), + Batch: []mcms.Operation{ + { + To: onRamp.Address(), + Data: tx.Data(), + Value: big.NewInt(0), + }, + }, + }) + timelocks[chainSel] = s.Chains[chainSel].Timelock.Address() + proposers[chainSel] = s.Chains[chainSel].ProposerMcm + } + } + if cfg.MCMS == nil { + return deployment.ChangesetOutput{}, nil + } + + p, err := proposalutils.BuildProposalFromBatches( + timelocks, + proposers, + batches, + "Update onramp destinations", + cfg.MCMS.MinDelay, + ) + if err != nil { + return deployment.ChangesetOutput{}, err + } + return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ + *p, + }}, nil +} + +type UpdateFeeQuoterDestsConfig struct { + UpdatesByChain map[uint64]map[uint64]fee_quoter.FeeQuoterDestChainConfig + // Disallow mixing MCMS/non-MCMS per chain for simplicity. + // (can still be acheived by calling this function multiple times) + MCMS *MCMSConfig +} + +func (cfg UpdateFeeQuoterDestsConfig) Validate(e deployment.Environment) error { + state, err := LoadOnchainState(e) + if err != nil { + return err + } + supportedChains := state.SupportedChains() + for chainSel, updates := range cfg.UpdatesByChain { + chainState, ok := state.Chains[chainSel] + if !ok { + return fmt.Errorf("chain %d not found in onchain state", chainSel) + } + if chainState.TestRouter == nil { + return fmt.Errorf("missing test router for chain %d", chainSel) + } + if chainState.Router == nil { + return fmt.Errorf("missing router for chain %d", chainSel) + } + if chainState.OnRamp == nil { + return fmt.Errorf("missing onramp onramp for chain %d", chainSel) + } + if err := commoncs.ValidateOwnership(e.GetContext(), cfg.MCMS != nil, e.Chains[chainSel].DeployerKey.From, chainState.Timelock.Address(), chainState.FeeQuoter); err != nil { + return err + } + + for destination := range updates { + // Destination cannot be an unknown destination. + if _, ok := supportedChains[destination]; !ok { + return fmt.Errorf("destination chain %d is not a supported %s", destination, chainState.OnRamp.Address()) + } + sc, err := chainState.OnRamp.GetStaticConfig(&bind.CallOpts{Context: e.GetContext()}) + if err != nil { + return fmt.Errorf("failed to get onramp static config %s: %w", chainState.OnRamp.Address(), err) + } + if destination == sc.ChainSelector { + return fmt.Errorf("cannot update onramp destination to the same chain") + } + } + } + return nil +} + +func UpdateFeeQuoterDests(e deployment.Environment, cfg UpdateFeeQuoterDestsConfig) (deployment.ChangesetOutput, error) { + if err := cfg.Validate(e); err != nil { + return deployment.ChangesetOutput{}, err + } + s, err := LoadOnchainState(e) + if err != nil { + return deployment.ChangesetOutput{}, err + } + var batches []timelock.BatchChainOperation + timelocks := make(map[uint64]common.Address) + proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + for chainSel, updates := range cfg.UpdatesByChain { + txOpts := e.Chains[chainSel].DeployerKey + txOpts.Context = e.GetContext() + if cfg.MCMS != nil { + txOpts = deployment.SimTransactOpts() + } + fq := s.Chains[chainSel].FeeQuoter + var args []fee_quoter.FeeQuoterDestChainConfigArgs + for destination, dc := range updates { + args = append(args, fee_quoter.FeeQuoterDestChainConfigArgs{ + DestChainSelector: destination, + DestChainConfig: dc, + }) + } + tx, err := fq.ApplyDestChainConfigUpdates(txOpts, args) + if err != nil { + return deployment.ChangesetOutput{}, err + } + if cfg.MCMS == nil { + if _, err := deployment.ConfirmIfNoError(e.Chains[chainSel], tx, err); err != nil { + return deployment.ChangesetOutput{}, err + } + } else { + batches = append(batches, timelock.BatchChainOperation{ + ChainIdentifier: mcms.ChainIdentifier(chainSel), + Batch: []mcms.Operation{ + { + To: fq.Address(), + Data: tx.Data(), + Value: big.NewInt(0), + }, + }, + }) + timelocks[chainSel] = s.Chains[chainSel].Timelock.Address() + proposers[chainSel] = s.Chains[chainSel].ProposerMcm + } + } + if cfg.MCMS == nil { + return deployment.ChangesetOutput{}, nil + } + + p, err := proposalutils.BuildProposalFromBatches( + timelocks, + proposers, + batches, + "Update fq destinations", + cfg.MCMS.MinDelay, + ) + if err != nil { + return deployment.ChangesetOutput{}, err + } + return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ + *p, + }}, nil +} + +type UpdateOffRampSourcesConfig struct { + UpdatesByChain map[uint64]map[uint64]OffRampSourceUpdate + MCMS *MCMSConfig +} + +type OffRampSourceUpdate struct { + IsEnabled bool // If false, disables the source by setting router to 0x0. + TestRouter bool // Flag for safety only allow specifying either router or testRouter. +} + +func (cfg UpdateOffRampSourcesConfig) Validate(e deployment.Environment) error { + state, err := LoadOnchainState(e) + if err != nil { + return err + } + supportedChains := state.SupportedChains() + for chainSel, updates := range cfg.UpdatesByChain { + chainState, ok := state.Chains[chainSel] + if !ok { + return fmt.Errorf("chain %d not found in onchain state", chainSel) + } + if chainState.TestRouter == nil { + return fmt.Errorf("missing test router for chain %d", chainSel) + } + if chainState.Router == nil { + return fmt.Errorf("missing router for chain %d", chainSel) + } + if chainState.OffRamp == nil { + return fmt.Errorf("missing onramp onramp for chain %d", chainSel) + } + if err := commoncs.ValidateOwnership(e.GetContext(), cfg.MCMS != nil, e.Chains[chainSel].DeployerKey.From, chainState.Timelock.Address(), chainState.OffRamp); err != nil { + return err + } + + for source := range updates { + // Source cannot be an unknown + if _, ok := supportedChains[source]; !ok { + return fmt.Errorf("source chain %d is not a supported chain %s", source, chainState.OffRamp.Address()) + } + + if source == chainSel { + return fmt.Errorf("cannot update offramp source to the same chain %d", source) + } + sourceChain := state.Chains[source] + // Source chain must have the onramp deployed. + // Note this also validates the specified source selector. + if sourceChain.OnRamp == nil { + return fmt.Errorf("missing onramp for source %d", source) + } + } + } + return nil +} + +// UpdateOffRampSources updates the offramp sources for each offramp. +func UpdateOffRampSources(e deployment.Environment, cfg UpdateOffRampSourcesConfig) (deployment.ChangesetOutput, error) { + if err := cfg.Validate(e); err != nil { + return deployment.ChangesetOutput{}, err + } + s, err := LoadOnchainState(e) + if err != nil { + return deployment.ChangesetOutput{}, err + } + var batches []timelock.BatchChainOperation + timelocks := make(map[uint64]common.Address) + proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + for chainSel, updates := range cfg.UpdatesByChain { + txOpts := e.Chains[chainSel].DeployerKey + txOpts.Context = e.GetContext() + if cfg.MCMS != nil { + txOpts = deployment.SimTransactOpts() + } + offRamp := s.Chains[chainSel].OffRamp + var args []offramp.OffRampSourceChainConfigArgs + for source, update := range updates { + router := common.HexToAddress("0x0") + if update.IsEnabled { + if update.TestRouter { + router = s.Chains[chainSel].TestRouter.Address() + } else { + router = s.Chains[chainSel].Router.Address() + } + } + onRamp := s.Chains[source].OnRamp + args = append(args, offramp.OffRampSourceChainConfigArgs{ + SourceChainSelector: source, + Router: router, + IsEnabled: update.IsEnabled, + OnRamp: common.LeftPadBytes(onRamp.Address().Bytes(), 32), + }) + } + tx, err := offRamp.ApplySourceChainConfigUpdates(txOpts, args) + if err != nil { + return deployment.ChangesetOutput{}, err + } + if cfg.MCMS == nil { + if _, err := deployment.ConfirmIfNoError(e.Chains[chainSel], tx, err); err != nil { + return deployment.ChangesetOutput{}, err + } + } else { + batches = append(batches, timelock.BatchChainOperation{ + ChainIdentifier: mcms.ChainIdentifier(chainSel), + Batch: []mcms.Operation{ + { + To: offRamp.Address(), + Data: tx.Data(), + Value: big.NewInt(0), + }, + }, + }) + timelocks[chainSel] = s.Chains[chainSel].Timelock.Address() + proposers[chainSel] = s.Chains[chainSel].ProposerMcm + } + } + if cfg.MCMS == nil { + return deployment.ChangesetOutput{}, nil + } + + p, err := proposalutils.BuildProposalFromBatches( + timelocks, + proposers, + batches, + "Update offramp sources", + cfg.MCMS.MinDelay, + ) + if err != nil { + return deployment.ChangesetOutput{}, err + } + return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ + *p, + }}, nil +} + +type UpdateRouterRampsConfig struct { + // TestRouter means the updates will be applied to the test router + // on all chains. Disallow mixing test router/non-test router per chain for simplicity. + TestRouter bool + UpdatesByChain map[uint64]RouterUpdates + MCMS *MCMSConfig +} + +type RouterUpdates struct { + OffRampUpdates map[uint64]bool + OnRampUpdates map[uint64]bool +} + +func (cfg UpdateRouterRampsConfig) Validate(e deployment.Environment) error { + state, err := LoadOnchainState(e) + if err != nil { + return err + } + supportedChains := state.SupportedChains() + for chainSel, update := range cfg.UpdatesByChain { + chainState, ok := state.Chains[chainSel] + if !ok { + return fmt.Errorf("chain %d not found in onchain state", chainSel) + } + if chainState.TestRouter == nil { + return fmt.Errorf("missing test router for chain %d", chainSel) + } + if chainState.Router == nil { + return fmt.Errorf("missing router for chain %d", chainSel) + } + if chainState.OffRamp == nil { + return fmt.Errorf("missing onramp onramp for chain %d", chainSel) + } + if err := commoncs.ValidateOwnership(e.GetContext(), cfg.MCMS != nil, e.Chains[chainSel].DeployerKey.From, chainState.Timelock.Address(), chainState.Router); err != nil { + return err + } + + for source := range update.OffRampUpdates { + // Source cannot be an unknown + if _, ok := supportedChains[source]; !ok { + return fmt.Errorf("source chain %d is not a supported chain %s", source, chainState.OffRamp.Address()) + } + if source == chainSel { + return fmt.Errorf("cannot update offramp source to the same chain %d", source) + } + sourceChain := state.Chains[source] + // Source chain must have the onramp deployed. + // Note this also validates the specified source selector. + if sourceChain.OnRamp == nil { + return fmt.Errorf("missing onramp for source %d", source) + } + } + for destination := range update.OnRampUpdates { + // Source cannot be an unknown + if _, ok := supportedChains[destination]; !ok { + return fmt.Errorf("dest chain %d is not a supported chain %s", destination, chainState.OffRamp.Address()) + } + if destination == chainSel { + return fmt.Errorf("cannot update onRamp dest to the same chain %d", destination) + } + destChain := state.Chains[destination] + if destChain.OffRamp == nil { + return fmt.Errorf("missing offramp for dest %d", destination) + } + } + + } + return nil +} + +// UpdateRouterRamps updates the on/offramps +// in either the router or test router for a series of chains. Use cases include: +// - Ramp upgrade. After deploying new ramps you can enable them on the test router and +// ensure it works e2e. Then enable the ramps on the real router. +// - New chain support. When adding a new chain, you can enable the new destination +// on all chains to support the new chain through the test router first. Once tested, +// Enable the new destination on the real router. +func UpdateRouterRamps(e deployment.Environment, cfg UpdateRouterRampsConfig) (deployment.ChangesetOutput, error) { + if err := cfg.Validate(e); err != nil { + return deployment.ChangesetOutput{}, err + } + s, err := LoadOnchainState(e) + if err != nil { + return deployment.ChangesetOutput{}, err + } + var batches []timelock.BatchChainOperation + timelocks := make(map[uint64]common.Address) + proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + for chainSel, update := range cfg.UpdatesByChain { + txOpts := e.Chains[chainSel].DeployerKey + txOpts.Context = e.GetContext() + if cfg.MCMS != nil { + txOpts = deployment.SimTransactOpts() + } + routerC := s.Chains[chainSel].Router + if cfg.TestRouter { + routerC = s.Chains[chainSel].TestRouter + } + // Note if we add distinct offramps per source to the state, + // we'll need to add support here for looking them up. + // For now its simple, all sources use the same offramp. + offRamp := s.Chains[chainSel].OffRamp + var removes, adds []router.RouterOffRamp + for source, enabled := range update.OffRampUpdates { + if enabled { + adds = append(adds, router.RouterOffRamp{ + SourceChainSelector: source, + OffRamp: offRamp.Address(), + }) + } else { + removes = append(removes, router.RouterOffRamp{ + SourceChainSelector: source, + OffRamp: offRamp.Address(), + }) + } + } + // Ditto here, only one onramp expected until 1.7. + onRamp := s.Chains[chainSel].OnRamp + var onRampUpdates []router.RouterOnRamp + for dest, enabled := range update.OnRampUpdates { + if enabled { + onRampUpdates = append(onRampUpdates, router.RouterOnRamp{ + DestChainSelector: dest, + OnRamp: onRamp.Address(), + }) + } else { + onRampUpdates = append(onRampUpdates, router.RouterOnRamp{ + DestChainSelector: dest, + OnRamp: common.HexToAddress("0x0"), + }) + } + } + tx, err := routerC.ApplyRampUpdates(txOpts, onRampUpdates, removes, adds) + if err != nil { + return deployment.ChangesetOutput{}, err + } + if cfg.MCMS == nil { + if _, err := deployment.ConfirmIfNoError(e.Chains[chainSel], tx, err); err != nil { + return deployment.ChangesetOutput{}, err + } + } else { + batches = append(batches, timelock.BatchChainOperation{ + ChainIdentifier: mcms.ChainIdentifier(chainSel), + Batch: []mcms.Operation{ + { + To: routerC.Address(), + Data: tx.Data(), + Value: big.NewInt(0), + }, + }, + }) + timelocks[chainSel] = s.Chains[chainSel].Timelock.Address() + proposers[chainSel] = s.Chains[chainSel].ProposerMcm + } + } + if cfg.MCMS == nil { + return deployment.ChangesetOutput{}, nil + } + + p, err := proposalutils.BuildProposalFromBatches( + timelocks, + proposers, + batches, + "Update router offramps", + cfg.MCMS.MinDelay, + ) + if err != nil { + return deployment.ChangesetOutput{}, err + } + return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ + *p, + }}, nil +} + +type SetOCR3OffRampConfig struct { + HomeChainSel uint64 + RemoteChainSels []uint64 + MCMS *MCMSConfig +} + +func (c SetOCR3OffRampConfig) Validate(e deployment.Environment) error { + state, err := LoadOnchainState(e) + if err != nil { + return err + } + if _, ok := state.Chains[c.HomeChainSel]; !ok { + return fmt.Errorf("home chain %d not found in onchain state", c.HomeChainSel) + } + for _, remote := range c.RemoteChainSels { + chainState, ok := state.Chains[remote] + if !ok { + return fmt.Errorf("remote chain %d not found in onchain state", remote) + } + if err := commoncs.ValidateOwnership(e.GetContext(), c.MCMS != nil, e.Chains[remote].DeployerKey.From, chainState.Timelock.Address(), chainState.OffRamp); err != nil { + return err + } + } + return nil +} + +// SetOCR3OffRamp will set the OCR3 offramp for the given chain. +// to the active configuration on CCIPHome. This +// is used to complete the candidate->active promotion cycle, it's +// run after the candidate is confirmed to be working correctly. +// Multichain is especially helpful for NOP rotations where we have +// to touch all the chain to change signers. +func SetOCR3OffRamp(e deployment.Environment, cfg SetOCR3OffRampConfig) (deployment.ChangesetOutput, error) { + if err := cfg.Validate(e); err != nil { + return deployment.ChangesetOutput{}, err + } + state, err := LoadOnchainState(e) + if err != nil { + return deployment.ChangesetOutput{}, err + } + var batches []timelock.BatchChainOperation + timelocks := make(map[uint64]common.Address) + proposers := make(map[uint64]*gethwrappers.ManyChainMultiSig) + for _, remote := range cfg.RemoteChainSels { + donID, err := internal.DonIDForChain( + state.Chains[cfg.HomeChainSel].CapabilityRegistry, + state.Chains[cfg.HomeChainSel].CCIPHome, + remote) + args, err := internal.BuildSetOCR3ConfigArgs(donID, state.Chains[cfg.HomeChainSel].CCIPHome, remote) + if err != nil { + return deployment.ChangesetOutput{}, err + } + set, err := isOCR3ConfigSetOnOffRamp(e.Logger, e.Chains[remote], state.Chains[remote].OffRamp, args) + if err != nil { + return deployment.ChangesetOutput{}, err + } + if set { + e.Logger.Infof("OCR3 config already set on offramp for chain %d", remote) + continue + } + txOpts := e.Chains[remote].DeployerKey + if cfg.MCMS != nil { + txOpts = deployment.SimTransactOpts() + } + offRamp := state.Chains[remote].OffRamp + tx, err := offRamp.SetOCR3Configs(txOpts, args) + if err != nil { + return deployment.ChangesetOutput{}, err + } + if cfg.MCMS == nil { + if _, err := deployment.ConfirmIfNoError(e.Chains[remote], tx, err); err != nil { + return deployment.ChangesetOutput{}, err + } + } else { + batches = append(batches, timelock.BatchChainOperation{ + ChainIdentifier: mcms.ChainIdentifier(remote), + Batch: []mcms.Operation{ + { + To: offRamp.Address(), + Data: tx.Data(), + Value: big.NewInt(0), + }, + }, + }) + timelocks[remote] = state.Chains[remote].Timelock.Address() + proposers[remote] = state.Chains[remote].ProposerMcm + } + } + if cfg.MCMS == nil { + return deployment.ChangesetOutput{}, nil + } + p, err := proposalutils.BuildProposalFromBatches( + timelocks, + proposers, + batches, + "Update OCR3 config", + cfg.MCMS.MinDelay, + ) + if err != nil { + return deployment.ChangesetOutput{}, err + } + e.Logger.Infof("Proposing OCR3 config update for", cfg.RemoteChainSels) + return deployment.ChangesetOutput{Proposals: []timelock.MCMSWithTimelockProposal{ + *p, + }}, nil +} + +func isOCR3ConfigSetOnOffRamp( + lggr logger.Logger, + chain deployment.Chain, + offRamp *offramp.OffRamp, + offrampOCR3Configs []offramp.MultiOCR3BaseOCRConfigArgs, +) (bool, error) { + mapOfframpOCR3Configs := make(map[cctypes.PluginType]offramp.MultiOCR3BaseOCRConfigArgs) + for _, config := range offrampOCR3Configs { + mapOfframpOCR3Configs[cctypes.PluginType(config.OcrPluginType)] = config + } + + for _, pluginType := range []cctypes.PluginType{cctypes.PluginTypeCCIPCommit, cctypes.PluginTypeCCIPExec} { + ocrConfig, err := offRamp.LatestConfigDetails(&bind.CallOpts{ + Context: context.Background(), + }, uint8(pluginType)) + if err != nil { + return false, fmt.Errorf("error fetching OCR3 config for plugin %s chain %s: %w", pluginType.String(), chain.String(), err) + } + lggr.Debugw("Fetched OCR3 Configs", + "MultiOCR3BaseOCRConfig.F", ocrConfig.ConfigInfo.F, + "MultiOCR3BaseOCRConfig.N", ocrConfig.ConfigInfo.N, + "MultiOCR3BaseOCRConfig.IsSignatureVerificationEnabled", ocrConfig.ConfigInfo.IsSignatureVerificationEnabled, + "Signers", ocrConfig.Signers, + "Transmitters", ocrConfig.Transmitters, + "configDigest", hex.EncodeToString(ocrConfig.ConfigInfo.ConfigDigest[:]), + "chain", chain.String(), + ) + // TODO: assertions to be done as part of full state + // resprentation validation CCIP-3047 + if mapOfframpOCR3Configs[pluginType].ConfigDigest != ocrConfig.ConfigInfo.ConfigDigest { + lggr.Infow("OCR3 config digest mismatch", "pluginType", pluginType.String()) + return false, nil + } + if mapOfframpOCR3Configs[pluginType].F != ocrConfig.ConfigInfo.F { + lggr.Infow("OCR3 config F mismatch", "pluginType", pluginType.String()) + return false, nil + } + if mapOfframpOCR3Configs[pluginType].IsSignatureVerificationEnabled != ocrConfig.ConfigInfo.IsSignatureVerificationEnabled { + lggr.Infow("OCR3 config signature verification mismatch", "pluginType", pluginType.String()) + return false, nil + } + if pluginType == cctypes.PluginTypeCCIPCommit { + // only commit will set signers, exec doesn't need them. + for i, signer := range mapOfframpOCR3Configs[pluginType].Signers { + if !bytes.Equal(signer.Bytes(), ocrConfig.Signers[i].Bytes()) { + lggr.Infow("OCR3 config signer mismatch", "pluginType", pluginType.String()) + return false, nil + } + } + } + for i, transmitter := range mapOfframpOCR3Configs[pluginType].Transmitters { + if !bytes.Equal(transmitter.Bytes(), ocrConfig.Transmitters[i].Bytes()) { + lggr.Infow("OCR3 config transmitter mismatch", "pluginType", pluginType.String()) + return false, nil + } + } + } + return true, nil +} diff --git a/deployment/ccip/changeset/cs_chain_contracts_test.go b/deployment/ccip/changeset/cs_chain_contracts_test.go new file mode 100644 index 00000000000..ad1b1a9f2b5 --- /dev/null +++ b/deployment/ccip/changeset/cs_chain_contracts_test.go @@ -0,0 +1,305 @@ +package changeset + +import ( + "testing" + + "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-testing-framework/lib/utils/testcontext" + commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" +) + +func TestUpdateOnRampsDests(t *testing.T) { + for _, tc := range []struct { + name string + mcmsEnabled bool + }{ + { + name: "MCMS enabled", + mcmsEnabled: true, + }, + { + name: "MCMS disabled", + mcmsEnabled: false, + }, + } { + t.Run(tc.name, func(t *testing.T) { + ctx := testcontext.Get(t) + // Default env just has 2 chains with all contracts + // deployed but no lanes. + tenv := NewMemoryEnvironment(t) + state, err := LoadOnchainState(tenv.Env) + require.NoError(t, err) + + allChains := maps.Keys(tenv.Env.Chains) + source := allChains[0] + dest := allChains[1] + + if tc.mcmsEnabled { + // Transfer ownership to timelock so that we can promote the zero digest later down the line. + transferToTimelock(t, tenv, state, source, dest) + } + + var mcmsConfig *MCMSConfig + if tc.mcmsEnabled { + mcmsConfig = &MCMSConfig{ + MinDelay: 0, + } + } + _, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(UpdateOnRampsDests), + Config: UpdateOnRampDestsConfig{ + UpdatesByChain: map[uint64]map[uint64]OnRampDestinationUpdate{ + source: { + dest: { + IsEnabled: true, + TestRouter: true, + AllowListEnabled: false, + }, + }, + dest: { + source: { + IsEnabled: true, + TestRouter: false, + AllowListEnabled: true, + }, + }, + }, + MCMS: mcmsConfig, + }, + }, + }) + require.NoError(t, err) + + // Assert the onramp configuration is as we expect. + sourceCfg, err := state.Chains[source].OnRamp.GetDestChainConfig(&bind.CallOpts{Context: ctx}, dest) + require.NoError(t, err) + require.Equal(t, state.Chains[source].TestRouter.Address(), sourceCfg.Router) + require.Equal(t, false, sourceCfg.AllowlistEnabled) + destCfg, err := state.Chains[dest].OnRamp.GetDestChainConfig(&bind.CallOpts{Context: ctx}, source) + require.NoError(t, err) + require.Equal(t, state.Chains[dest].Router.Address(), destCfg.Router) + require.Equal(t, true, destCfg.AllowlistEnabled) + }) + } +} + +func TestUpdateOffRampsSources(t *testing.T) { + for _, tc := range []struct { + name string + mcmsEnabled bool + }{ + { + name: "MCMS enabled", + mcmsEnabled: true, + }, + { + name: "MCMS disabled", + mcmsEnabled: false, + }, + } { + t.Run(tc.name, func(t *testing.T) { + ctx := testcontext.Get(t) + tenv := NewMemoryEnvironment(t) + state, err := LoadOnchainState(tenv.Env) + require.NoError(t, err) + + allChains := maps.Keys(tenv.Env.Chains) + source := allChains[0] + dest := allChains[1] + + if tc.mcmsEnabled { + // Transfer ownership to timelock so that we can promote the zero digest later down the line. + transferToTimelock(t, tenv, state, source, dest) + } + + var mcmsConfig *MCMSConfig + if tc.mcmsEnabled { + mcmsConfig = &MCMSConfig{ + MinDelay: 0, + } + } + _, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(UpdateOffRampSources), + Config: UpdateOffRampSourcesConfig{ + UpdatesByChain: map[uint64]map[uint64]OffRampSourceUpdate{ + source: { + dest: { + IsEnabled: true, + TestRouter: true, + }, + }, + dest: { + source: { + IsEnabled: true, + TestRouter: false, + }, + }, + }, + MCMS: mcmsConfig, + }, + }, + }) + require.NoError(t, err) + + // Assert the offramp configuration is as we expect. + sourceCfg, err := state.Chains[source].OffRamp.GetSourceChainConfig(&bind.CallOpts{Context: ctx}, dest) + require.NoError(t, err) + require.Equal(t, state.Chains[source].TestRouter.Address(), sourceCfg.Router) + destCfg, err := state.Chains[dest].OffRamp.GetSourceChainConfig(&bind.CallOpts{Context: ctx}, source) + require.NoError(t, err) + require.Equal(t, state.Chains[dest].Router.Address(), destCfg.Router) + }) + } +} + +func TestUpdateFQDests(t *testing.T) { + for _, tc := range []struct { + name string + mcmsEnabled bool + }{ + { + name: "MCMS enabled", + mcmsEnabled: true, + }, + { + name: "MCMS disabled", + mcmsEnabled: false, + }, + } { + t.Run(tc.name, func(t *testing.T) { + ctx := testcontext.Get(t) + tenv := NewMemoryEnvironment(t) + state, err := LoadOnchainState(tenv.Env) + require.NoError(t, err) + + allChains := maps.Keys(tenv.Env.Chains) + source := allChains[0] + dest := allChains[1] + + if tc.mcmsEnabled { + // Transfer ownership to timelock so that we can promote the zero digest later down the line. + transferToTimelock(t, tenv, state, source, dest) + } + + var mcmsConfig *MCMSConfig + if tc.mcmsEnabled { + mcmsConfig = &MCMSConfig{ + MinDelay: 0, + } + } + + fqCfg1 := DefaultFeeQuoterDestChainConfig() + fqCfg2 := DefaultFeeQuoterDestChainConfig() + fqCfg2.DestGasOverhead = 1000 + _, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(UpdateFeeQuoterDests), + Config: UpdateFeeQuoterDestsConfig{ + UpdatesByChain: map[uint64]map[uint64]fee_quoter.FeeQuoterDestChainConfig{ + source: { + dest: fqCfg1, + }, + dest: { + source: fqCfg2, + }, + }, + MCMS: mcmsConfig, + }, + }, + }) + require.NoError(t, err) + + // Assert the fq configuration is as we expect. + source2destCfg, err := state.Chains[source].FeeQuoter.GetDestChainConfig(&bind.CallOpts{Context: ctx}, dest) + require.NoError(t, err) + AssertEqualFeeConfig(t, fqCfg1, source2destCfg) + dest2sourceCfg, err := state.Chains[dest].FeeQuoter.GetDestChainConfig(&bind.CallOpts{Context: ctx}, source) + require.NoError(t, err) + AssertEqualFeeConfig(t, fqCfg2, dest2sourceCfg) + }) + } +} + +func TestUpdateRouterRamps(t *testing.T) { + for _, tc := range []struct { + name string + mcmsEnabled bool + }{ + { + name: "MCMS enabled", + mcmsEnabled: true, + }, + { + name: "MCMS disabled", + mcmsEnabled: false, + }, + } { + t.Run(tc.name, func(t *testing.T) { + ctx := testcontext.Get(t) + tenv := NewMemoryEnvironment(t) + state, err := LoadOnchainState(tenv.Env) + require.NoError(t, err) + + allChains := maps.Keys(tenv.Env.Chains) + source := allChains[0] + dest := allChains[1] + + if tc.mcmsEnabled { + // Transfer ownership to timelock so that we can promote the zero digest later down the line. + transferToTimelock(t, tenv, state, source, dest) + } + + var mcmsConfig *MCMSConfig + if tc.mcmsEnabled { + mcmsConfig = &MCMSConfig{ + MinDelay: 0, + } + } + + // Updates test router. + _, err = commonchangeset.ApplyChangesets(t, tenv.Env, tenv.TimelockContracts(t), []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(UpdateRouterRamps), + Config: UpdateRouterRampsConfig{ + TestRouter: true, + UpdatesByChain: map[uint64]RouterUpdates{ + source: { + OffRampUpdates: map[uint64]bool{ + dest: true, + }, + OnRampUpdates: map[uint64]bool{ + dest: true, + }, + }, + dest: { + OffRampUpdates: map[uint64]bool{ + source: true, + }, + OnRampUpdates: map[uint64]bool{ + source: true, + }, + }, + }, + MCMS: mcmsConfig, + }, + }, + }) + require.NoError(t, err) + + // Assert the router configuration is as we expect. + source2destOnRampTest, err := state.Chains[source].TestRouter.GetOnRamp(&bind.CallOpts{Context: ctx}, dest) + require.NoError(t, err) + require.Equal(t, state.Chains[source].OnRamp.Address(), source2destOnRampTest) + source2destOnRampReal, err := state.Chains[source].Router.GetOnRamp(&bind.CallOpts{Context: ctx}, dest) + require.NoError(t, err) + require.Equal(t, common.HexToAddress("0x0"), source2destOnRampReal) + }) + } +} diff --git a/deployment/ccip/changeset/cs_initial_add_chain.go b/deployment/ccip/changeset/cs_initial_add_chain.go deleted file mode 100644 index 4f8b2ac2722..00000000000 --- a/deployment/ccip/changeset/cs_initial_add_chain.go +++ /dev/null @@ -1,532 +0,0 @@ -package changeset - -import ( - "bytes" - "context" - "encoding/hex" - "fmt" - "os" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" - - "github.com/smartcontractkit/chainlink-ccip/chainconfig" - "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" - "github.com/smartcontractkit/chainlink-ccip/pluginconfig" - "github.com/smartcontractkit/chainlink-common/pkg/config" - "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink-common/pkg/merklemulti" - - "github.com/smartcontractkit/chainlink/deployment" - "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" - "github.com/smartcontractkit/chainlink/deployment/common/types" - cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_home" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" -) - -var _ deployment.ChangeSet[NewChainsConfig] = ConfigureNewChains - -// ConfigureNewChains enables new chains as destination(s) for CCIP -// It performs the following steps per chain: -// - addChainConfig + AddDON (candidate->primary promotion i.e. init) on the home chain -// - SetOCR3Config on the remote chain -// ConfigureNewChains assumes that the home chain is already enabled and all CCIP contracts are already deployed. -func ConfigureNewChains(env deployment.Environment, c NewChainsConfig) (deployment.ChangesetOutput, error) { - if err := c.Validate(); err != nil { - return deployment.ChangesetOutput{}, fmt.Errorf("invalid NewChainsConfig: %w", err) - } - err := configureChain(env, c) - if err != nil { - env.Logger.Errorw("Failed to configure chain", "err", err) - return deployment.ChangesetOutput{}, deployment.MaybeDataErr(err) - } - return deployment.ChangesetOutput{ - Proposals: []timelock.MCMSWithTimelockProposal{}, - AddressBook: nil, - JobSpecs: nil, - }, nil -} - -type CCIPOCRParams struct { - OCRParameters types.OCRParameters - // Note contains pointers to Arb feeds for prices - CommitOffChainConfig pluginconfig.CommitOffchainConfig - // Note ontains USDC config - ExecuteOffChainConfig pluginconfig.ExecuteOffchainConfig -} - -func (c CCIPOCRParams) Validate() error { - if err := c.OCRParameters.Validate(); err != nil { - return fmt.Errorf("invalid OCR parameters: %w", err) - } - if err := c.CommitOffChainConfig.Validate(); err != nil { - return fmt.Errorf("invalid commit off-chain config: %w", err) - } - if err := c.ExecuteOffChainConfig.Validate(); err != nil { - return fmt.Errorf("invalid execute off-chain config: %w", err) - } - return nil -} - -type NewChainsConfig struct { - // Common to all chains - HomeChainSel uint64 - FeedChainSel uint64 - // Per chain config - ChainConfigByChain map[uint64]CCIPOCRParams -} - -func (c NewChainsConfig) Chains() []uint64 { - chains := make([]uint64, 0, len(c.ChainConfigByChain)) - for chain := range c.ChainConfigByChain { - chains = append(chains, chain) - } - return chains -} - -func (c NewChainsConfig) Validate() error { - if err := deployment.IsValidChainSelector(c.HomeChainSel); err != nil { - return fmt.Errorf("invalid home chain selector: %d - %w", c.HomeChainSel, err) - } - if err := deployment.IsValidChainSelector(c.FeedChainSel); err != nil { - return fmt.Errorf("invalid feed chain selector: %d - %w", c.FeedChainSel, err) - } - // Validate chain config - for chain, cfg := range c.ChainConfigByChain { - if err := cfg.Validate(); err != nil { - return fmt.Errorf("invalid OCR params for chain %d: %w", chain, err) - } - if cfg.CommitOffChainConfig.PriceFeedChainSelector != ccipocr3.ChainSelector(c.FeedChainSel) { - return fmt.Errorf("chain %d has invalid feed chain selector", chain) - } - } - return nil -} - -// DefaultOCRParams returns the default OCR parameters for a chain, -// except for a few values which must be parameterized (passed as arguments). -func DefaultOCRParams( - feedChainSel uint64, - tokenInfo map[ccipocr3.UnknownEncodedAddress]pluginconfig.TokenInfo, - tokenDataObservers []pluginconfig.TokenDataObserverConfig, -) CCIPOCRParams { - return CCIPOCRParams{ - OCRParameters: types.OCRParameters{ - DeltaProgress: internal.DeltaProgress, - DeltaResend: internal.DeltaResend, - DeltaInitial: internal.DeltaInitial, - DeltaRound: internal.DeltaRound, - DeltaGrace: internal.DeltaGrace, - DeltaCertifiedCommitRequest: internal.DeltaCertifiedCommitRequest, - DeltaStage: internal.DeltaStage, - Rmax: internal.Rmax, - MaxDurationQuery: internal.MaxDurationQuery, - MaxDurationObservation: internal.MaxDurationObservation, - MaxDurationShouldAcceptAttestedReport: internal.MaxDurationShouldAcceptAttestedReport, - MaxDurationShouldTransmitAcceptedReport: internal.MaxDurationShouldTransmitAcceptedReport, - }, - ExecuteOffChainConfig: pluginconfig.ExecuteOffchainConfig{ - BatchGasLimit: internal.BatchGasLimit, - RelativeBoostPerWaitHour: internal.RelativeBoostPerWaitHour, - InflightCacheExpiry: *config.MustNewDuration(internal.InflightCacheExpiry), - RootSnoozeTime: *config.MustNewDuration(internal.RootSnoozeTime), - MessageVisibilityInterval: *config.MustNewDuration(internal.FirstBlockAge), - BatchingStrategyID: internal.BatchingStrategyID, - TokenDataObservers: tokenDataObservers, - }, - CommitOffChainConfig: pluginconfig.CommitOffchainConfig{ - RemoteGasPriceBatchWriteFrequency: *config.MustNewDuration(internal.RemoteGasPriceBatchWriteFrequency), - TokenPriceBatchWriteFrequency: *config.MustNewDuration(internal.TokenPriceBatchWriteFrequency), - TokenInfo: tokenInfo, - PriceFeedChainSelector: ccipocr3.ChainSelector(feedChainSel), - NewMsgScanBatchSize: merklemulti.MaxNumberTreeLeaves, - MaxReportTransmissionCheckAttempts: 5, - RMNEnabled: os.Getenv("ENABLE_RMN") == "true", // only enabled in manual test - RMNSignaturesTimeout: 30 * time.Minute, - MaxMerkleTreeSize: merklemulti.MaxNumberTreeLeaves, - SignObservationPrefix: "chainlink ccip 1.6 rmn observation", - }, - } -} - -// configureChain assumes the all the Home chain contracts and CCIP contracts are deployed -// It does - -// 1. addChainConfig for each chain in CCIPHome -// 2. Registers the nodes with the capability registry -// 3. SetOCR3Config on the remote chain -func configureChain( - e deployment.Environment, - c NewChainsConfig, -) error { - if e.OCRSecrets.IsEmpty() { - return fmt.Errorf("OCR secrets are empty") - } - nodes, err := deployment.NodeInfo(e.NodeIDs, e.Offchain) - if err != nil || len(nodes) == 0 { - e.Logger.Errorw("Failed to get node info", "err", err) - return err - } - existingState, err := LoadOnchainState(e) - if err != nil { - e.Logger.Errorw("Failed to load existing onchain state", "err") - return err - } - homeChain := e.Chains[c.HomeChainSel] - capReg := existingState.Chains[c.HomeChainSel].CapabilityRegistry - if capReg == nil { - e.Logger.Errorw("Failed to get capability registry", "chain", homeChain.String()) - return fmt.Errorf("capability registry not found") - } - ccipHome := existingState.Chains[c.HomeChainSel].CCIPHome - if ccipHome == nil { - e.Logger.Errorw("Failed to get ccip home", "chain", homeChain.String(), "err", err) - return fmt.Errorf("ccip home not found") - } - rmnHome := existingState.Chains[c.HomeChainSel].RMNHome - if rmnHome == nil { - e.Logger.Errorw("Failed to get rmn home", "chain", homeChain.String(), "err", err) - return fmt.Errorf("rmn home not found") - } - - for chainSel, chainConfig := range c.ChainConfigByChain { - chain, _ := e.Chains[chainSel] - chainState, ok := existingState.Chains[chain.Selector] - if !ok { - return fmt.Errorf("chain state not found for chain %d", chain.Selector) - } - if chainState.OffRamp == nil { - return fmt.Errorf("off ramp not found for chain %d", chain.Selector) - } - _, err = addChainConfig( - e.Logger, - e.Chains[c.HomeChainSel], - ccipHome, - chain.Selector, - nodes.NonBootstraps().PeerIDs()) - if err != nil { - return err - } - // For each chain, we create a DON on the home chain (2 OCR instances) - if err := addDON( - e.Logger, - e.OCRSecrets, - capReg, - ccipHome, - rmnHome.Address(), - chainState.OffRamp, - chain, - e.Chains[c.HomeChainSel], - nodes.NonBootstraps(), - chainConfig, - ); err != nil { - e.Logger.Errorw("Failed to add DON", "err", err) - return err - } - } - - return nil -} - -func setupConfigInfo(chainSelector uint64, readers [][32]byte, fChain uint8, cfg []byte) ccip_home.CCIPHomeChainConfigArgs { - return ccip_home.CCIPHomeChainConfigArgs{ - ChainSelector: chainSelector, - ChainConfig: ccip_home.CCIPHomeChainConfig{ - Readers: readers, - FChain: fChain, - Config: cfg, - }, - } -} - -func isChainConfigEqual(a, b ccip_home.CCIPHomeChainConfig) bool { - mapReader := make(map[[32]byte]struct{}) - for i := range a.Readers { - mapReader[a.Readers[i]] = struct{}{} - } - for i := range b.Readers { - if _, ok := mapReader[b.Readers[i]]; !ok { - return false - } - } - return bytes.Equal(a.Config, b.Config) && - a.FChain == b.FChain -} - -func addChainConfig( - lggr logger.Logger, - h deployment.Chain, - ccipConfig *ccip_home.CCIPHome, - chainSelector uint64, - p2pIDs [][32]byte, -) (ccip_home.CCIPHomeChainConfigArgs, error) { - // First Add CCIPOCRParams that includes all p2pIDs as readers - encodedExtraChainConfig, err := chainconfig.EncodeChainConfig(chainconfig.ChainConfig{ - GasPriceDeviationPPB: ccipocr3.NewBigIntFromInt64(1000), - DAGasPriceDeviationPPB: ccipocr3.NewBigIntFromInt64(0), - OptimisticConfirmations: 1, - }) - if err != nil { - return ccip_home.CCIPHomeChainConfigArgs{}, err - } - chainConfig := setupConfigInfo(chainSelector, p2pIDs, uint8(len(p2pIDs)/3), encodedExtraChainConfig) - existingCfg, err := ccipConfig.GetChainConfig(nil, chainSelector) - if err != nil { - return ccip_home.CCIPHomeChainConfigArgs{}, fmt.Errorf("get chain config for selector %d: %w", chainSelector, err) - } - if isChainConfigEqual(existingCfg, chainConfig.ChainConfig) { - lggr.Infow("Chain config already exists, not applying again", - "homeChain", h.String(), - "addedChain", chainSelector, - "chainConfig", chainConfig, - ) - return chainConfig, nil - } - tx, err := ccipConfig.ApplyChainConfigUpdates(h.DeployerKey, nil, []ccip_home.CCIPHomeChainConfigArgs{ - chainConfig, - }) - if _, err := deployment.ConfirmIfNoError(h, tx, err); err != nil { - return ccip_home.CCIPHomeChainConfigArgs{}, err - } - lggr.Infow("Applied chain config updates", "homeChain", h.String(), "addedChain", chainSelector, "chainConfig", chainConfig) - return chainConfig, nil -} - -// createDON creates one DON with 2 plugins (commit and exec) -// It first set a new candidate for the DON with the first plugin type and AddDON on capReg -// Then for subsequent operations it uses UpdateDON to promote the first plugin to the active deployment -// and to set candidate and promote it for the second plugin -func createDON( - lggr logger.Logger, - capReg *capabilities_registry.CapabilitiesRegistry, - ccipHome *ccip_home.CCIPHome, - ocr3Configs map[cctypes.PluginType]ccip_home.CCIPHomeOCR3Config, - home deployment.Chain, - newChainSel uint64, - nodes deployment.Nodes, -) error { - donID, err := internal.DonIDForChain(capReg, ccipHome, newChainSel) - if err != nil { - return fmt.Errorf("fetch don id for chain: %w", err) - } - if donID != 0 { - lggr.Infow("DON already exists not adding it again", "donID", donID, "chain", newChainSel) - return ValidateCCIPHomeConfigSetUp(lggr, capReg, ccipHome, newChainSel) - } - - commitConfig, ok := ocr3Configs[cctypes.PluginTypeCCIPCommit] - if !ok { - return fmt.Errorf("missing commit plugin in ocr3Configs") - } - - execConfig, ok := ocr3Configs[cctypes.PluginTypeCCIPExec] - if !ok { - return fmt.Errorf("missing exec plugin in ocr3Configs") - } - - latestDon, err := internal.LatestCCIPDON(capReg) - if err != nil { - return err - } - - donID = latestDon.Id + 1 - - err = internal.SetupCommitDON(lggr, donID, commitConfig, capReg, home, nodes, ccipHome) - if err != nil { - return fmt.Errorf("setup commit don: %w", err) - } - - // TODO: bug in contract causing this to not work as expected. - err = internal.SetupExecDON(lggr, donID, execConfig, capReg, home, nodes, ccipHome) - if err != nil { - return fmt.Errorf("setup exec don: %w", err) - } - return ValidateCCIPHomeConfigSetUp(lggr, capReg, ccipHome, newChainSel) -} - -func addDON( - lggr logger.Logger, - ocrSecrets deployment.OCRSecrets, - capReg *capabilities_registry.CapabilitiesRegistry, - ccipHome *ccip_home.CCIPHome, - rmnHomeAddress common.Address, - offRamp *offramp.OffRamp, - dest deployment.Chain, - home deployment.Chain, - nodes deployment.Nodes, - ocrParams CCIPOCRParams, -) error { - ocrConfigs, err := internal.BuildOCR3ConfigForCCIPHome( - ocrSecrets, offRamp, dest, nodes, rmnHomeAddress, ocrParams.OCRParameters, ocrParams.CommitOffChainConfig, ocrParams.ExecuteOffChainConfig) - if err != nil { - return err - } - err = createDON(lggr, capReg, ccipHome, ocrConfigs, home, dest.Selector, nodes) - if err != nil { - return err - } - don, err := internal.LatestCCIPDON(capReg) - if err != nil { - return err - } - lggr.Infow("Added DON", "donID", don.Id) - - offrampOCR3Configs, err := internal.BuildSetOCR3ConfigArgs(don.Id, ccipHome, dest.Selector) - if err != nil { - return err - } - lggr.Infow("Setting OCR3 Configs", - "offrampOCR3Configs", offrampOCR3Configs, - "configDigestCommit", hex.EncodeToString(offrampOCR3Configs[cctypes.PluginTypeCCIPCommit].ConfigDigest[:]), - "configDigestExec", hex.EncodeToString(offrampOCR3Configs[cctypes.PluginTypeCCIPExec].ConfigDigest[:]), - "chainSelector", dest.Selector, - ) - - // check if OCR3 config is already set on offramp - ocr3ConfigSet, err := isOCR3ConfigSetOnOffRamp(lggr, dest, offRamp, offrampOCR3Configs) - if err != nil { - return fmt.Errorf("error checking if OCR3 config is set on offramp: %w", err) - } - if ocr3ConfigSet { - lggr.Infow("OCR3 config already set on offramp, not applying again", "chain", dest.String()) - return nil - } - tx, err := offRamp.SetOCR3Configs(dest.DeployerKey, offrampOCR3Configs) - if _, err := deployment.ConfirmIfNoError(dest, tx, err); err != nil { - return err - } - lggr.Infow("Set OCR3 Configs", "chain", dest.String()) - // now check if OCR3 config is set on offramp - ocr3ConfigSet, err = isOCR3ConfigSetOnOffRamp(lggr, dest, offRamp, offrampOCR3Configs) - if err != nil { - return fmt.Errorf("error checking if OCR3 config is set on offramp: %w", err) - } - if !ocr3ConfigSet { - return fmt.Errorf("OCR3 config not set on offramp properly, check logs, chain %s", dest.String()) - } - return nil -} - -func isOCR3ConfigSetOnOffRamp( - lggr logger.Logger, - chain deployment.Chain, - offRamp *offramp.OffRamp, - offrampOCR3Configs []offramp.MultiOCR3BaseOCRConfigArgs, -) (bool, error) { - mapOfframpOCR3Configs := make(map[cctypes.PluginType]offramp.MultiOCR3BaseOCRConfigArgs) - for _, config := range offrampOCR3Configs { - mapOfframpOCR3Configs[cctypes.PluginType(config.OcrPluginType)] = config - } - - for _, pluginType := range []cctypes.PluginType{cctypes.PluginTypeCCIPCommit, cctypes.PluginTypeCCIPExec} { - ocrConfig, err := offRamp.LatestConfigDetails(&bind.CallOpts{ - Context: context.Background(), - }, uint8(pluginType)) - if err != nil { - return false, fmt.Errorf("error fetching OCR3 config for plugin %s chain %s: %w", pluginType.String(), chain.String(), err) - } - lggr.Debugw("Fetched OCR3 Configs", - "MultiOCR3BaseOCRConfig.F", ocrConfig.ConfigInfo.F, - "MultiOCR3BaseOCRConfig.N", ocrConfig.ConfigInfo.N, - "MultiOCR3BaseOCRConfig.IsSignatureVerificationEnabled", ocrConfig.ConfigInfo.IsSignatureVerificationEnabled, - "Signers", ocrConfig.Signers, - "Transmitters", ocrConfig.Transmitters, - "configDigest", hex.EncodeToString(ocrConfig.ConfigInfo.ConfigDigest[:]), - "chain", chain.String(), - ) - // TODO: assertions to be done as part of full state - // resprentation validation CCIP-3047 - if mapOfframpOCR3Configs[pluginType].ConfigDigest != ocrConfig.ConfigInfo.ConfigDigest { - lggr.Infow("OCR3 config digest mismatch", "pluginType", pluginType.String()) - return false, nil - } - if mapOfframpOCR3Configs[pluginType].F != ocrConfig.ConfigInfo.F { - lggr.Infow("OCR3 config F mismatch", "pluginType", pluginType.String()) - return false, nil - } - if mapOfframpOCR3Configs[pluginType].IsSignatureVerificationEnabled != ocrConfig.ConfigInfo.IsSignatureVerificationEnabled { - lggr.Infow("OCR3 config signature verification mismatch", "pluginType", pluginType.String()) - return false, nil - } - if pluginType == cctypes.PluginTypeCCIPCommit { - // only commit will set signers, exec doesn't need them. - for i, signer := range mapOfframpOCR3Configs[pluginType].Signers { - if !bytes.Equal(signer.Bytes(), ocrConfig.Signers[i].Bytes()) { - lggr.Infow("OCR3 config signer mismatch", "pluginType", pluginType.String()) - return false, nil - } - } - } - for i, transmitter := range mapOfframpOCR3Configs[pluginType].Transmitters { - if !bytes.Equal(transmitter.Bytes(), ocrConfig.Transmitters[i].Bytes()) { - lggr.Infow("OCR3 config transmitter mismatch", "pluginType", pluginType.String()) - return false, nil - } - } - } - return true, nil -} - -// ValidateCCIPHomeConfigSetUp checks that the commit and exec active and candidate configs are set up correctly -func ValidateCCIPHomeConfigSetUp( - lggr logger.Logger, - capReg *capabilities_registry.CapabilitiesRegistry, - ccipHome *ccip_home.CCIPHome, - chainSel uint64, -) error { - // fetch DONID - donID, err := internal.DonIDForChain(capReg, ccipHome, chainSel) - if err != nil { - return fmt.Errorf("fetch don id for chain: %w", err) - } - if donID == 0 { - return fmt.Errorf("don id for chain (%d) does not exist", chainSel) - } - - // final sanity checks on configs. - commitConfigs, err := ccipHome.GetAllConfigs(&bind.CallOpts{ - //Pending: true, - }, donID, uint8(cctypes.PluginTypeCCIPCommit)) - if err != nil { - return fmt.Errorf("get all commit configs: %w", err) - } - commitActiveDigest, err := ccipHome.GetActiveDigest(nil, donID, uint8(cctypes.PluginTypeCCIPCommit)) - if err != nil { - return fmt.Errorf("get active commit digest: %w", err) - } - lggr.Debugw("Fetched active commit digest", "commitActiveDigest", hex.EncodeToString(commitActiveDigest[:])) - commitCandidateDigest, err := ccipHome.GetCandidateDigest(nil, donID, uint8(cctypes.PluginTypeCCIPCommit)) - if err != nil { - return fmt.Errorf("get commit candidate digest: %w", err) - } - lggr.Debugw("Fetched candidate commit digest", "commitCandidateDigest", hex.EncodeToString(commitCandidateDigest[:])) - if commitConfigs.ActiveConfig.ConfigDigest == [32]byte{} { - return fmt.Errorf( - "active config digest is empty for commit, expected nonempty, donID: %d, cfg: %+v, config digest from GetActiveDigest call: %x, config digest from GetCandidateDigest call: %x", - donID, commitConfigs.ActiveConfig, commitActiveDigest, commitCandidateDigest) - } - if commitConfigs.CandidateConfig.ConfigDigest != [32]byte{} { - return fmt.Errorf( - "candidate config digest is nonempty for commit, expected empty, donID: %d, cfg: %+v, config digest from GetCandidateDigest call: %x, config digest from GetActiveDigest call: %x", - donID, commitConfigs.CandidateConfig, commitCandidateDigest, commitActiveDigest) - } - - execConfigs, err := ccipHome.GetAllConfigs(nil, donID, uint8(cctypes.PluginTypeCCIPExec)) - if err != nil { - return fmt.Errorf("get all exec configs: %w", err) - } - lggr.Debugw("Fetched exec configs", - "ActiveConfig.ConfigDigest", hex.EncodeToString(execConfigs.ActiveConfig.ConfigDigest[:]), - "CandidateConfig.ConfigDigest", hex.EncodeToString(execConfigs.CandidateConfig.ConfigDigest[:]), - ) - if execConfigs.ActiveConfig.ConfigDigest == [32]byte{} { - return fmt.Errorf("active config digest is empty for exec, expected nonempty, cfg: %v", execConfigs.ActiveConfig) - } - if execConfigs.CandidateConfig.ConfigDigest != [32]byte{} { - return fmt.Errorf("candidate config digest is nonempty for exec, expected empty, cfg: %v", execConfigs.CandidateConfig) - } - return nil -} diff --git a/deployment/ccip/changeset/cs_initial_add_chain_test.go b/deployment/ccip/changeset/cs_initial_add_chain_test.go deleted file mode 100644 index 7e155b82ed1..00000000000 --- a/deployment/ccip/changeset/cs_initial_add_chain_test.go +++ /dev/null @@ -1,93 +0,0 @@ -package changeset - -import ( - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/chainlink-ccip/pluginconfig" - "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" - "github.com/stretchr/testify/require" - - commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" - "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" -) - -func TestInitialAddChainAppliedTwice(t *testing.T) { - t.Parallel() - // This already applies the initial add chain changeset. - e := NewMemoryEnvironment(t) - - state, err := LoadOnchainState(e.Env) - require.NoError(t, err) - - // now try to apply it again for the second time - // Build the per chain config. - allChains := e.Env.AllChainSelectors() - tokenConfig := NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds) - chainConfigs := make(map[uint64]CCIPOCRParams) - timelockContractsPerChain := make(map[uint64]*proposalutils.TimelockExecutionContracts) - - for _, chain := range allChains { - timelockContractsPerChain[chain] = &proposalutils.TimelockExecutionContracts{ - Timelock: state.Chains[chain].Timelock, - CallProxy: state.Chains[chain].CallProxy, - } - tokenInfo := tokenConfig.GetTokenInfo(e.Env.Logger, state.Chains[chain].LinkToken, state.Chains[chain].Weth9) - ocrParams := DefaultOCRParams(e.FeedChainSel, tokenInfo, []pluginconfig.TokenDataObserverConfig{}) - chainConfigs[chain] = ocrParams - } - e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, timelockContractsPerChain, []commonchangeset.ChangesetApplication{ - { - Changeset: commonchangeset.WrapChangeSet(ConfigureNewChains), - Config: NewChainsConfig{ - HomeChainSel: e.HomeChainSel, - FeedChainSel: e.FeedChainSel, - ChainConfigByChain: chainConfigs, - }, - }, - }) - require.NoError(t, err) - // send requests - chain1, chain2 := allChains[0], allChains[1] - _, err = AddLanes(e.Env, AddLanesConfig{ - LaneConfigs: []LaneConfig{ - { - SourceSelector: chain1, - DestSelector: chain2, - InitialPricesBySource: DefaultInitialPrices, - FeeQuoterDestChain: DefaultFeeQuoterDestChainConfig(), - TestRouter: true, - }, - }, - }) - require.NoError(t, err) - ReplayLogs(t, e.Env.Offchain, e.ReplayBlocks) - // Need to keep track of the block number for each chain so that event subscription can be done from that block. - startBlocks := make(map[uint64]*uint64) - // Send a message from each chain to every other chain. - expectedSeqNumExec := make(map[SourceDestPair][]uint64) - expectedSeqNum := make(map[SourceDestPair]uint64) - latesthdr, err := e.Env.Chains[chain2].Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[chain2] = &block - msgSentEvent := TestSendRequest(t, e.Env, state, chain1, chain2, true, router.ClientEVM2AnyMessage{ - Receiver: common.LeftPadBytes(state.Chains[chain2].Receiver.Address().Bytes(), 32), - Data: []byte("hello"), - TokenAmounts: nil, - FeeToken: common.HexToAddress("0x0"), - ExtraArgs: nil, - }) - - expectedSeqNum[SourceDestPair{ - SourceChainSelector: chain1, - DestChainSelector: chain2, - }] = msgSentEvent.SequenceNumber - expectedSeqNumExec[SourceDestPair{ - SourceChainSelector: chain1, - DestChainSelector: chain2, - }] = []uint64{msgSentEvent.SequenceNumber} - ConfirmCommitForAllWithExpectedSeqNums(t, e.Env, state, expectedSeqNum, startBlocks) - ConfirmExecWithSeqNrsForAll(t, e.Env, state, expectedSeqNumExec, startBlocks) -} diff --git a/deployment/ccip/changeset/internal/deploy_home_chain.go b/deployment/ccip/changeset/internal/deploy_home_chain.go index e4c97cae326..2c401fd8006 100644 --- a/deployment/ccip/changeset/internal/deploy_home_chain.go +++ b/deployment/ccip/changeset/internal/deploy_home_chain.go @@ -11,8 +11,6 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" - "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink-ccip/pluginconfig" "github.com/smartcontractkit/chainlink/deployment" @@ -48,6 +46,10 @@ const ( MaxDurationObservation = 5 * time.Second MaxDurationShouldAcceptAttestedReport = 10 * time.Second MaxDurationShouldTransmitAcceptedReport = 10 * time.Second + + GasPriceDeviationPPB = 1000 + DAGasPriceDeviationPPB = 0 + OptimisticConfirmations = 1 ) var ( @@ -188,255 +190,6 @@ func BuildSetOCR3ConfigArgs( return offrampOCR3Configs, nil } -func SetupExecDON( - lggr logger.Logger, - donID uint32, - execConfig ccip_home.CCIPHomeOCR3Config, - capReg *capabilities_registry.CapabilitiesRegistry, - home deployment.Chain, - nodes deployment.Nodes, - ccipHome *ccip_home.CCIPHome, -) error { - encodedSetCandidateCall, err := CCIPHomeABI.Pack( - "setCandidate", - donID, - execConfig.PluginType, - execConfig, - [32]byte{}, - ) - if err != nil { - return fmt.Errorf("pack set candidate call: %w", err) - } - - // set candidate call - tx, err := capReg.UpdateDON( - home.DeployerKey, - donID, - nodes.PeerIDs(), - []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: CCIPCapabilityID, - Config: encodedSetCandidateCall, - }, - }, - false, - nodes.DefaultF(), - ) - if err != nil { - return fmt.Errorf("update don w/ exec config: %w", err) - } - - if _, err := deployment.ConfirmIfNoError(home, tx, err); err != nil { - return fmt.Errorf("confirm update don w/ exec config: %w", err) - } - lggr.Infow("Updated DON with exec config", "chain", home.String(), "donID", donID, "txHash", tx.Hash().Hex(), "setCandidateCall", encodedSetCandidateCall) - - execCandidateDigest, err := ccipHome.GetCandidateDigest(nil, donID, execConfig.PluginType) - if err != nil { - return fmt.Errorf("get exec candidate digest 1st time: %w", err) - } - - if execCandidateDigest == [32]byte{} { - return fmt.Errorf("candidate digest is empty, expected nonempty") - } - lggr.Infow("Got exec candidate digest", "chain", home.String(), "donID", donID, "execCandidateDigest", execCandidateDigest) - // promote candidate call - encodedPromotionCall, err := CCIPHomeABI.Pack( - "promoteCandidateAndRevokeActive", - donID, - execConfig.PluginType, - execCandidateDigest, - [32]byte{}, - ) - if err != nil { - return fmt.Errorf("pack promotion call: %w", err) - } - - tx, err = capReg.UpdateDON( - home.DeployerKey, - donID, - nodes.PeerIDs(), - []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: CCIPCapabilityID, - Config: encodedPromotionCall, - }, - }, - false, - nodes.DefaultF(), - ) - if err != nil { - return fmt.Errorf("update don w/ exec config: %w", err) - } - bn, err := deployment.ConfirmIfNoError(home, tx, err) - if err != nil { - return fmt.Errorf("confirm update don w/ exec config: %w", err) - } - if bn == 0 { - return fmt.Errorf("UpdateDON tx not confirmed") - } - lggr.Infow("Promoted exec candidate", "chain", home.String(), "donID", donID, "txHash", tx.Hash().Hex(), "promotionCall", encodedPromotionCall) - // check if candidate digest is promoted - pEvent, err := ccipHome.FilterConfigPromoted(&bind.FilterOpts{ - Context: context.Background(), - Start: bn, - }, [][32]byte{execCandidateDigest}) - if err != nil { - return fmt.Errorf("filter exec config promoted: %w", err) - } - if !pEvent.Next() { - return fmt.Errorf("exec config not promoted") - } - // check that candidate digest is empty. - execCandidateDigest, err = ccipHome.GetCandidateDigest(nil, donID, execConfig.PluginType) - if err != nil { - return fmt.Errorf("get exec candidate digest 2nd time: %w", err) - } - - if execCandidateDigest != [32]byte{} { - return fmt.Errorf("candidate digest is nonempty after promotion, expected empty") - } - - // check that active digest is non-empty. - execActiveDigest, err := ccipHome.GetActiveDigest(nil, donID, uint8(types.PluginTypeCCIPExec)) - if err != nil { - return fmt.Errorf("get active exec digest: %w", err) - } - - if execActiveDigest == [32]byte{} { - return fmt.Errorf("active exec digest is empty, expected nonempty") - } - - execConfigs, err := ccipHome.GetAllConfigs(nil, donID, uint8(types.PluginTypeCCIPExec)) - if err != nil { - return fmt.Errorf("get all exec configs 2nd time: %w", err) - } - - // log the above info - lggr.Infow("completed exec DON creation and promotion", - "donID", donID, - "execCandidateDigest", execCandidateDigest, - "execActiveDigest", execActiveDigest, - "execCandidateDigestFromGetAllConfigs", execConfigs.CandidateConfig.ConfigDigest, - "execActiveDigestFromGetAllConfigs", execConfigs.ActiveConfig.ConfigDigest, - ) - - return nil -} - -func SetupCommitDON( - lggr logger.Logger, - donID uint32, - commitConfig ccip_home.CCIPHomeOCR3Config, - capReg *capabilities_registry.CapabilitiesRegistry, - home deployment.Chain, - nodes deployment.Nodes, - ccipHome *ccip_home.CCIPHome, -) error { - encodedSetCandidateCall, err := CCIPHomeABI.Pack( - "setCandidate", - donID, - commitConfig.PluginType, - commitConfig, - [32]byte{}, - ) - if err != nil { - return fmt.Errorf("pack set candidate call: %w", err) - } - tx, err := capReg.AddDON(home.DeployerKey, nodes.PeerIDs(), []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: CCIPCapabilityID, - Config: encodedSetCandidateCall, - }, - }, false, false, nodes.DefaultF()) - if err != nil { - return fmt.Errorf("add don w/ commit config: %w", err) - } - - if _, err := deployment.ConfirmIfNoError(home, tx, err); err != nil { - return fmt.Errorf("confirm add don w/ commit config: %w", err) - } - lggr.Debugw("Added DON with commit config", "chain", home.String(), "donID", donID, "txHash", tx.Hash().Hex(), "setCandidateCall", encodedSetCandidateCall) - commitCandidateDigest, err := ccipHome.GetCandidateDigest(nil, donID, commitConfig.PluginType) - if err != nil { - return fmt.Errorf("get commit candidate digest: %w", err) - } - - if commitCandidateDigest == [32]byte{} { - return fmt.Errorf("candidate digest is empty, expected nonempty") - } - lggr.Debugw("Got commit candidate digest", "chain", home.String(), "donID", donID, "commitCandidateDigest", commitCandidateDigest) - - encodedPromotionCall, err := CCIPHomeABI.Pack( - "promoteCandidateAndRevokeActive", - donID, - commitConfig.PluginType, - commitCandidateDigest, - [32]byte{}, - ) - if err != nil { - return fmt.Errorf("pack promotion call: %w", err) - } - - tx, err = capReg.UpdateDON( - home.DeployerKey, - donID, - nodes.PeerIDs(), - []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: CCIPCapabilityID, - Config: encodedPromotionCall, - }, - }, - false, - nodes.DefaultF(), - ) - if err != nil { - return fmt.Errorf("update don w/ commit config: %w", err) - } - - if _, err := deployment.ConfirmIfNoError(home, tx, err); err != nil { - return fmt.Errorf("confirm update don w/ commit config: %w", err) - } - lggr.Debugw("Promoted commit candidate", "chain", home.String(), "donID", donID, "txHash", tx.Hash().Hex(), "promotionCall", encodedPromotionCall) - - // check that candidate digest is empty. - commitCandidateDigest, err = ccipHome.GetCandidateDigest(nil, donID, commitConfig.PluginType) - if err != nil { - return fmt.Errorf("get commit candidate digest 2nd time: %w", err) - } - - if commitCandidateDigest != [32]byte{} { - return fmt.Errorf("candidate digest is nonempty after promotion, expected empty") - } - - // check that active digest is non-empty. - commitActiveDigest, err := ccipHome.GetActiveDigest(nil, donID, uint8(types.PluginTypeCCIPCommit)) - if err != nil { - return fmt.Errorf("get active commit digest: %w", err) - } - - if commitActiveDigest == [32]byte{} { - return fmt.Errorf("active commit digest is empty, expected nonempty") - } - - commitConfigs, err := ccipHome.GetAllConfigs(nil, donID, uint8(types.PluginTypeCCIPCommit)) - if err != nil { - return fmt.Errorf("get all commit configs 2nd time: %w", err) - } - - // log the above information - lggr.Infow("completed commit DON creation and promotion", - "donID", donID, - "commitCandidateDigest", commitCandidateDigest, - "commitActiveDigest", commitActiveDigest, - "commitCandidateDigestFromGetAllConfigs", commitConfigs.CandidateConfig.ConfigDigest, - "commitActiveDigestFromGetAllConfigs", commitConfigs.ActiveConfig.ConfigDigest, - ) - - return nil -} - func BuildOCR3ConfigForCCIPHome( ocrSecrets deployment.OCRSecrets, offRamp *offramp.OffRamp, diff --git a/deployment/ccip/changeset/state.go b/deployment/ccip/changeset/state.go index 2403f3f7cc2..ccd6176a9f7 100644 --- a/deployment/ccip/changeset/state.go +++ b/deployment/ccip/changeset/state.go @@ -289,6 +289,14 @@ func (s CCIPOnChainState) GetAllTimeLocksForChains(chains []uint64) (map[uint64] return timelocks, nil } +func (s CCIPOnChainState) SupportedChains() map[uint64]struct{} { + chains := make(map[uint64]struct{}) + for chain := range s.Chains { + chains[chain] = struct{}{} + } + return chains +} + func (s CCIPOnChainState) View(chains []uint64) (map[string]view.ChainView, error) { m := make(map[string]view.ChainView) for _, chainSelector := range chains { diff --git a/deployment/ccip/changeset/test_assertions.go b/deployment/ccip/changeset/test_assertions.go index a114e52b361..bcfb49250d4 100644 --- a/deployment/ccip/changeset/test_assertions.go +++ b/deployment/ccip/changeset/test_assertions.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" @@ -636,3 +637,19 @@ func executionStateToString(state uint8) string { return "UNKNOWN" } } + +func AssertEqualFeeConfig(t *testing.T, want, have fee_quoter.FeeQuoterDestChainConfig) { + assert.Equal(t, want.DestGasOverhead, have.DestGasOverhead) + assert.Equal(t, want.IsEnabled, have.IsEnabled) + assert.Equal(t, want.ChainFamilySelector, have.ChainFamilySelector) + assert.Equal(t, want.DefaultTokenDestGasOverhead, have.DefaultTokenDestGasOverhead) + assert.Equal(t, want.DefaultTokenFeeUSDCents, have.DefaultTokenFeeUSDCents) + assert.Equal(t, want.DefaultTxGasLimit, have.DefaultTxGasLimit) + assert.Equal(t, want.DestGasPerPayloadByte, have.DestGasPerPayloadByte) + assert.Equal(t, want.DestGasPerDataAvailabilityByte, have.DestGasPerDataAvailabilityByte) + assert.Equal(t, want.DestDataAvailabilityMultiplierBps, have.DestDataAvailabilityMultiplierBps) + assert.Equal(t, want.DestDataAvailabilityOverheadGas, have.DestDataAvailabilityOverheadGas) + assert.Equal(t, want.MaxDataBytes, have.MaxDataBytes) + assert.Equal(t, want.MaxNumberOfTokensPerMsg, have.MaxNumberOfTokensPerMsg) + assert.Equal(t, want.MaxPerMsgGasLimit, have.MaxPerMsgGasLimit) +} diff --git a/deployment/ccip/changeset/test_environment.go b/deployment/ccip/changeset/test_environment.go index cb0760cee1c..8c2ea88b276 100644 --- a/deployment/ccip/changeset/test_environment.go +++ b/deployment/ccip/changeset/test_environment.go @@ -9,14 +9,18 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zapcore" + + "github.com/smartcontractkit/chainlink-ccip/chainconfig" cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" "github.com/smartcontractkit/chainlink-ccip/pluginconfig" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" - "github.com/stretchr/testify/require" - "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" "github.com/smartcontractkit/chainlink/deployment" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" @@ -34,8 +38,9 @@ const ( ) type TestConfigs struct { - Type EnvType // set by env var CCIP_V16_TEST_ENV, defaults to Memory - CreateJob bool + Type EnvType // set by env var CCIP_V16_TEST_ENV, defaults to Memory + CreateJob bool + // TODO: This should be CreateContracts so the booleans make sense? CreateJobAndContracts bool Chains int // only used in memory mode, for docker mode, this is determined by the integration-test config toml input NumOfUsersPerChain int // only used in memory mode, for docker mode, this is determined by the integration-test config toml input @@ -177,6 +182,19 @@ type DeployedEnv struct { Users map[uint64][]*bind.TransactOpts } +func (d *DeployedEnv) TimelockContracts(t *testing.T) map[uint64]*proposalutils.TimelockExecutionContracts { + timelocks := make(map[uint64]*proposalutils.TimelockExecutionContracts) + state, err := LoadOnchainState(d.Env) + require.NoError(t, err) + for chain, chainState := range state.Chains { + timelocks[chain] = &proposalutils.TimelockExecutionContracts{ + Timelock: chainState.Timelock, + CallProxy: chainState.CallProxy, + } + } + return timelocks +} + func (d *DeployedEnv) SetupJobs(t *testing.T) { ctx := testcontext.Get(t) out, err := CCIPCapabilityJobspec(d.Env, struct{}{}) @@ -277,6 +295,7 @@ func NewEnvironment(t *testing.T, tc *TestConfigs, tEnv TestEnvironment) Deploye crConfig := DeployTestContracts(t, lggr, ab, dEnv.HomeChainSel, dEnv.FeedChainSel, dEnv.Env.Chains, tc.LinkPrice, tc.WethPrice) tEnv.StartNodes(t, tc, crConfig) dEnv = tEnv.DeployedEnvironment() + // TODO: Should use ApplyChangesets here. envNodes, err := deployment.NodeInfo(dEnv.Env.NodeIDs, dEnv.Env.Offchain) require.NoError(t, err) dEnv.Env.ExistingAddresses = ab @@ -383,8 +402,11 @@ func NewEnvironmentWithJobsAndContracts(t *testing.T, tc *TestConfigs, tEnv Test }}) } // Build the per chain config. - chainConfigs := make(map[uint64]CCIPOCRParams) + ocrConfigs := make(map[uint64]CCIPOCRParams) + chainConfigs := make(map[uint64]ChainConfig) timelockContractsPerChain := make(map[uint64]*proposalutils.TimelockExecutionContracts) + nodeInfo, err := deployment.NodeInfo(e.Env.NodeIDs, e.Env.Offchain) + require.NoError(t, err) for _, chain := range allChains { timelockContractsPerChain[chain] = &proposalutils.TimelockExecutionContracts{ Timelock: state.Chains[chain].Timelock, @@ -395,16 +417,65 @@ func NewEnvironmentWithJobsAndContracts(t *testing.T, tc *TestConfigs, tEnv Test if tc.OCRConfigOverride != nil { ocrParams = tc.OCRConfigOverride(ocrParams) } - chainConfigs[chain] = ocrParams + ocrConfigs[chain] = ocrParams + chainConfigs[chain] = ChainConfig{ + Readers: nodeInfo.NonBootstraps().PeerIDs(), + FChain: uint8(len(nodeInfo.NonBootstraps().PeerIDs()) / 3), + EncodableChainConfig: chainconfig.ChainConfig{ + GasPriceDeviationPPB: cciptypes.BigInt{Int: big.NewInt(internal.GasPriceDeviationPPB)}, + DAGasPriceDeviationPPB: cciptypes.BigInt{Int: big.NewInt(internal.DAGasPriceDeviationPPB)}, + OptimisticConfirmations: internal.OptimisticConfirmations, + }, + } } // Deploy second set of changesets to deploy and configure the CCIP contracts. e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, timelockContractsPerChain, []commonchangeset.ChangesetApplication{ { - Changeset: commonchangeset.WrapChangeSet(ConfigureNewChains), - Config: NewChainsConfig{ - HomeChainSel: e.HomeChainSel, - FeedChainSel: e.FeedChainSel, - ChainConfigByChain: chainConfigs, + // Add the chain configs for the new chains. + Changeset: commonchangeset.WrapChangeSet(UpdateChainConfig), + Config: UpdateChainConfigConfig{ + HomeChainSelector: e.HomeChainSel, + RemoteChainAdds: chainConfigs, + }, + }, + { + // Add the DONs and candidate commit OCR instances for the chain. + Changeset: commonchangeset.WrapChangeSet(AddDonAndSetCandidateChangeset), + Config: AddDonAndSetCandidateChangesetConfig{ + SetCandidateConfigBase{ + HomeChainSelector: e.HomeChainSel, + FeedChainSelector: e.FeedChainSel, + OCRConfigPerRemoteChainSelector: ocrConfigs, + PluginType: types.PluginTypeCCIPCommit, + }, + }, + }, + { + // Add the exec OCR instances for the new chains. + Changeset: commonchangeset.WrapChangeSet(SetCandidateChangeset), + Config: SetCandidateChangesetConfig{ + SetCandidateConfigBase{ + HomeChainSelector: e.HomeChainSel, + FeedChainSelector: e.FeedChainSel, + OCRConfigPerRemoteChainSelector: ocrConfigs, + PluginType: types.PluginTypeCCIPExec, + }, + }, + }, + { + // Promote everything + Changeset: commonchangeset.WrapChangeSet(PromoteAllCandidatesChangeset), + Config: PromoteAllCandidatesChangesetConfig{ + HomeChainSelector: e.HomeChainSel, + RemoteChainSelectors: allChains, + }, + }, + { + // Enable the OCR config on the remote chains. + Changeset: commonchangeset.WrapChangeSet(SetOCR3OffRamp), + Config: SetOCR3OffRampConfig{ + HomeChainSel: e.HomeChainSel, + RemoteChainSels: allChains, }, }, { diff --git a/deployment/common/changeset/deploy_mcms_with_timelock.go b/deployment/common/changeset/deploy_mcms_with_timelock.go index c36e1f1575b..06f9aba6164 100644 --- a/deployment/common/changeset/deploy_mcms_with_timelock.go +++ b/deployment/common/changeset/deploy_mcms_with_timelock.go @@ -1,6 +1,12 @@ package changeset import ( + "context" + "fmt" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/changeset/internal" "github.com/smartcontractkit/chainlink/deployment/common/types" @@ -18,3 +24,16 @@ func DeployMCMSWithTimelock(e deployment.Environment, cfgByChain map[uint64]type } return deployment.ChangesetOutput{AddressBook: newAddresses}, nil } + +func ValidateOwnership(ctx context.Context, mcms bool, deployerKey, timelock common.Address, contract Ownable) error { + owner, err := contract.Owner(&bind.CallOpts{Context: ctx}) + if err != nil { + return fmt.Errorf("failed to get owner: %w", err) + } + if mcms && owner != timelock { + return fmt.Errorf("%s not owned by deployer key", contract.Address()) + } else if !mcms && owner != deployerKey { + return fmt.Errorf("%s not owned by deployer key", contract.Address()) + } + return nil +} diff --git a/deployment/common/proposalutils/propose.go b/deployment/common/proposalutils/propose.go index 32a5bcdfda2..baf506cb2f8 100644 --- a/deployment/common/proposalutils/propose.go +++ b/deployment/common/proposalutils/propose.go @@ -40,7 +40,13 @@ func BuildProposalMetadata( } // BuildProposalFromBatches Given batches of operations, we build the metadata and timelock addresses of those opartions -// We then return a proposal that can be executed and signed +// We then return a proposal that can be executed and signed. +// You can specify multiple batches for the same chain, but the only +// usecase to do that would be you have a batch that can't fit in a single +// transaction due to gas or calldata constraints of the chain. +// The batches are specified separately because we eventually intend +// to support user-specified cross chain ordering of batch execution by the tooling itself. +// TODO: Can/should merge timelocks and proposers into a single map for the chain. func BuildProposalFromBatches( timelocksPerChain map[uint64]common.Address, proposerMcmsesPerChain map[uint64]*gethwrappers.ManyChainMultiSig, From a01ed0ff111d29857abcffc6ef4769552ce6c3e2 Mon Sep 17 00:00:00 2001 From: Matthew Pendrey Date: Wed, 18 Dec 2024 18:52:38 +0000 Subject: [PATCH 22/27] Preperation for register unregister execution capability (#15760) * common bump * move aggregator * message cache to own package * lint * mod tidy * lint * generate * revert dispatcher revert * dispatcher mock --- core/capabilities/launcher.go | 3 +- .../remote/aggregation/default_mode.go | 58 ++++++++++++++ .../remote/aggregation/default_mode_test.go | 51 ++++++++++++ core/capabilities/remote/dispatcher.go | 28 +++---- core/capabilities/remote/dispatcher_test.go | 30 ++++---- .../remote/executable/endtoend_test.go | 34 +------- .../executable/request/client_request.go | 2 +- .../executable/request/client_request_test.go | 14 ++-- .../executable/request/server_request.go | 8 +- .../executable/request/server_request_test.go | 4 +- core/capabilities/remote/executable/server.go | 21 ++--- .../{ => messagecache}/message_cache.go | 17 ++-- .../{ => messagecache}/message_cache_test.go | 32 ++++---- core/capabilities/remote/trigger_publisher.go | 34 ++++---- .../capabilities/remote/trigger_subscriber.go | 30 ++++---- .../remote/trigger_subscriber_test.go | 1 - .../remote/types/mocks/dispatcher.go | 34 ++++---- core/capabilities/remote/types/types.go | 4 +- core/capabilities/remote/utils.go | 59 ++------------ core/capabilities/remote/utils_test.go | 77 +++++-------------- 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 +- 30 files changed, 287 insertions(+), 284 deletions(-) create mode 100644 core/capabilities/remote/aggregation/default_mode.go create mode 100644 core/capabilities/remote/aggregation/default_mode_test.go rename core/capabilities/remote/{ => messagecache}/message_cache.go (81%) rename core/capabilities/remote/{ => messagecache}/message_cache_test.go (59%) diff --git a/core/capabilities/launcher.go b/core/capabilities/launcher.go index 98318853e2a..51df7eeebfc 100644 --- a/core/capabilities/launcher.go +++ b/core/capabilities/launcher.go @@ -19,6 +19,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/values" "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/aggregation" "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/executable" remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" "github.com/smartcontractkit/chainlink/v2/core/capabilities/streams" @@ -280,7 +281,7 @@ func (w *launcher) addRemoteCapabilities(ctx context.Context, myDON registrysync w.lggr, ) } else { - aggregator = remote.NewDefaultModeAggregator(uint32(remoteDON.F) + 1) + aggregator = aggregation.NewDefaultModeAggregator(uint32(remoteDON.F) + 1) } // TODO: We need to implement a custom, Mercury-specific diff --git a/core/capabilities/remote/aggregation/default_mode.go b/core/capabilities/remote/aggregation/default_mode.go new file mode 100644 index 00000000000..3d5e262920f --- /dev/null +++ b/core/capabilities/remote/aggregation/default_mode.go @@ -0,0 +1,58 @@ +package aggregation + +import ( + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + + commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" + remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" +) + +// Default MODE Aggregator needs a configurable number of identical responses for aggregation to succeed +type defaultModeAggregator struct { + minIdenticalResponses uint32 +} + +var _ remotetypes.Aggregator = &defaultModeAggregator{} + +func NewDefaultModeAggregator(minIdenticalResponses uint32) *defaultModeAggregator { + return &defaultModeAggregator{ + minIdenticalResponses: minIdenticalResponses, + } +} + +func (a *defaultModeAggregator) Aggregate(_ string, responses [][]byte) (commoncap.TriggerResponse, error) { + found, err := AggregateModeRaw(responses, a.minIdenticalResponses) + if err != nil { + return commoncap.TriggerResponse{}, fmt.Errorf("failed to aggregate responses, err: %w", err) + } + + unmarshaled, err := pb.UnmarshalTriggerResponse(found) + if err != nil { + return commoncap.TriggerResponse{}, fmt.Errorf("failed to unmarshal aggregated responses, err: %w", err) + } + return unmarshaled, nil +} + +func AggregateModeRaw(elemList [][]byte, minIdenticalResponses uint32) ([]byte, error) { + hashToCount := make(map[string]uint32) + var found []byte + for _, elem := range elemList { + hasher := sha256.New() + hasher.Write(elem) + sha := hex.EncodeToString(hasher.Sum(nil)) + hashToCount[sha]++ + if hashToCount[sha] >= minIdenticalResponses { + found = elem + // update in case we find another elem with an even higher count + minIdenticalResponses = hashToCount[sha] + } + } + if found == nil { + return nil, errors.New("not enough identical responses found") + } + return found, nil +} diff --git a/core/capabilities/remote/aggregation/default_mode_test.go b/core/capabilities/remote/aggregation/default_mode_test.go new file mode 100644 index 00000000000..7c7d615e17a --- /dev/null +++ b/core/capabilities/remote/aggregation/default_mode_test.go @@ -0,0 +1,51 @@ +package aggregation + +import ( + "testing" + + "github.com/stretchr/testify/require" + + commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" + "github.com/smartcontractkit/chainlink-common/pkg/values" +) + +var ( + triggerEvent1 = map[string]any{"event": "triggerEvent1"} + triggerEvent2 = map[string]any{"event": "triggerEvent2"} +) + +func TestDefaultModeAggregator_Aggregate(t *testing.T) { + val, err := values.NewMap(triggerEvent1) + require.NoError(t, err) + capResponse1 := commoncap.TriggerResponse{ + Event: commoncap.TriggerEvent{ + Outputs: val, + }, + Err: nil, + } + marshaled1, err := pb.MarshalTriggerResponse(capResponse1) + require.NoError(t, err) + + val2, err := values.NewMap(triggerEvent2) + require.NoError(t, err) + capResponse2 := commoncap.TriggerResponse{ + Event: commoncap.TriggerEvent{ + Outputs: val2, + }, + Err: nil, + } + marshaled2, err := pb.MarshalTriggerResponse(capResponse2) + require.NoError(t, err) + + agg := NewDefaultModeAggregator(2) + _, err = agg.Aggregate("", [][]byte{marshaled1}) + require.Error(t, err) + + _, err = agg.Aggregate("", [][]byte{marshaled1, marshaled2}) + require.Error(t, err) + + res, err := agg.Aggregate("", [][]byte{marshaled1, marshaled2, marshaled1}) + require.NoError(t, err) + require.Equal(t, res, capResponse1) +} diff --git a/core/capabilities/remote/dispatcher.go b/core/capabilities/remote/dispatcher.go index e3229d35c1e..905eda9d72d 100644 --- a/core/capabilities/remote/dispatcher.go +++ b/core/capabilities/remote/dispatcher.go @@ -3,6 +3,7 @@ package remote import ( "context" "fmt" + "strconv" "sync" "time" @@ -42,8 +43,8 @@ type dispatcher struct { } type key struct { - capId string - donId uint32 + capID string + donID uint32 } var _ services.Service = &dispatcher{} @@ -74,7 +75,7 @@ func (d *dispatcher) Start(ctx context.Context) error { d.peer = d.peerWrapper.GetPeer() d.peerID = d.peer.ID() if d.peer == nil { - return fmt.Errorf("peer is not initialized") + return errors.New("peer is not initialized") } d.wg.Add(1) go func() { @@ -103,13 +104,13 @@ type receiver struct { ch chan *types.MessageBody } -func (d *dispatcher) SetReceiver(capabilityId string, donId uint32, rec types.Receiver) error { +func (d *dispatcher) SetReceiver(capabilityID string, donID uint32, rec types.Receiver) error { d.mu.Lock() defer d.mu.Unlock() - k := key{capabilityId, donId} + k := key{capabilityID, donID} _, ok := d.receivers[k] if ok { - return fmt.Errorf("%w: receiver already exists for capability %s and don %d", ErrReceiverExists, capabilityId, donId) + return fmt.Errorf("%w: receiver already exists for capability %s and don %d", ErrReceiverExists, capabilityID, donID) } receiverCh := make(chan *types.MessageBody, d.cfg.ReceiverBufferSize()) @@ -134,23 +135,24 @@ func (d *dispatcher) SetReceiver(capabilityId string, donId uint32, rec types.Re ch: receiverCh, } - d.lggr.Debugw("receiver set", "capabilityId", capabilityId, "donId", donId) + d.lggr.Debugw("receiver set", "capabilityId", capabilityID, "donId", donID) return nil } -func (d *dispatcher) RemoveReceiver(capabilityId string, donId uint32) { +func (d *dispatcher) RemoveReceiver(capabilityID string, donID uint32) { d.mu.Lock() defer d.mu.Unlock() - receiverKey := key{capabilityId, donId} + receiverKey := key{capabilityID, donID} if receiver, ok := d.receivers[receiverKey]; ok { receiver.cancel() delete(d.receivers, receiverKey) - d.lggr.Debugw("receiver removed", "capabilityId", capabilityId, "donId", donId) + d.lggr.Debugw("receiver removed", "capabilityId", capabilityID, "donId", donID) } } func (d *dispatcher) Send(peerID p2ptypes.PeerID, msgBody *types.MessageBody) error { + //nolint:gosec // disable G115 msgBody.Version = uint32(d.cfg.SupportedVersion()) msgBody.Sender = d.peerID[:] msgBody.Receiver = peerID[:] @@ -194,17 +196,17 @@ func (d *dispatcher) receive() { receiver, ok := d.receivers[k] d.mu.RUnlock() if !ok { - d.lggr.Debugw("received message for unregistered capability", "capabilityId", SanitizeLogString(k.capId), "donId", k.donId) + d.lggr.Debugw("received message for unregistered capability", "capabilityId", SanitizeLogString(k.capID), "donId", k.donID) d.tryRespondWithError(msg.Sender, body, types.Error_CAPABILITY_NOT_FOUND) continue } receiverQueueUsage := float64(len(receiver.ch)) / float64(d.cfg.ReceiverBufferSize()) - capReceiveChannelUsage.WithLabelValues(k.capId, fmt.Sprint(k.donId)).Set(receiverQueueUsage) + capReceiveChannelUsage.WithLabelValues(k.capID, strconv.FormatUint(uint64(k.donID), 10)).Set(receiverQueueUsage) select { case receiver.ch <- body: default: - d.lggr.Warnw("receiver channel full, dropping message", "capabilityId", k.capId, "donId", k.donId) + d.lggr.Warnw("receiver channel full, dropping message", "capabilityId", k.capID, "donId", k.donID) } } } diff --git a/core/capabilities/remote/dispatcher_test.go b/core/capabilities/remote/dispatcher_test.go index 50edc5f3530..fbc9dbb4b49 100644 --- a/core/capabilities/remote/dispatcher_test.go +++ b/core/capabilities/remote/dispatcher_test.go @@ -104,13 +104,13 @@ func TestDispatcher_CleanStartClose(t *testing.T) { func TestDispatcher_Receive(t *testing.T) { lggr := logger.TestLogger(t) ctx := testutils.Context(t) - privKey1, peerId1 := newKeyPair(t) - _, peerId2 := newKeyPair(t) + privKey1, peerID1 := newKeyPair(t) + _, peerID2 := newKeyPair(t) peer := mocks.NewPeer(t) recvCh := make(chan p2ptypes.Message) peer.On("Receive", mock.Anything).Return((<-chan p2ptypes.Message)(recvCh)) - peer.On("ID", mock.Anything).Return(peerId2) + peer.On("ID", mock.Anything).Return(peerID2) wrapper := mocks.NewPeerWrapper(t) wrapper.On("GetPeer").Return(peer) signer := mocks.NewSigner(t) @@ -131,39 +131,39 @@ func TestDispatcher_Receive(t *testing.T) { require.NoError(t, dispatcher.Start(ctx)) rcv := newReceiver() - err = dispatcher.SetReceiver(capId1, donId1, rcv) + err = dispatcher.SetReceiver(capID1, donID1, rcv) require.NoError(t, err) // supported capability - recvCh <- encodeAndSign(t, privKey1, peerId1, peerId2, capId1, donId1, []byte(payload1)) + recvCh <- encodeAndSign(t, privKey1, peerID1, peerID2, capID1, donID1, []byte(payload1)) // unknown capability - recvCh <- encodeAndSign(t, privKey1, peerId1, peerId2, capId2, donId1, []byte(payload1)) + recvCh <- encodeAndSign(t, privKey1, peerID1, peerID2, capID2, donID1, []byte(payload1)) // sender doesn't match - invalid := encodeAndSign(t, privKey1, peerId1, peerId2, capId2, donId1, []byte(payload1)) - invalid.Sender = peerId2 + invalid := encodeAndSign(t, privKey1, peerID1, peerID2, capID2, donID1, []byte(payload1)) + invalid.Sender = peerID2 recvCh <- invalid // supported capability again - recvCh <- encodeAndSign(t, privKey1, peerId1, peerId2, capId1, donId1, []byte(payload2)) + recvCh <- encodeAndSign(t, privKey1, peerID1, peerID2, capID1, donID1, []byte(payload2)) m := <-rcv.ch require.Equal(t, payload1, string(m.Payload)) m = <-rcv.ch require.Equal(t, payload2, string(m.Payload)) - dispatcher.RemoveReceiver(capId1, donId1) + dispatcher.RemoveReceiver(capID1, donID1) require.NoError(t, dispatcher.Close()) } func TestDispatcher_RespondWithError(t *testing.T) { lggr := logger.TestLogger(t) ctx := testutils.Context(t) - privKey1, peerId1 := newKeyPair(t) - _, peerId2 := newKeyPair(t) + privKey1, peerID1 := newKeyPair(t) + _, peerID2 := newKeyPair(t) peer := mocks.NewPeer(t) recvCh := make(chan p2ptypes.Message) peer.On("Receive", mock.Anything).Return((<-chan p2ptypes.Message)(recvCh)) - peer.On("ID", mock.Anything).Return(peerId2) + peer.On("ID", mock.Anything).Return(peerID2) sendCh := make(chan p2ptypes.PeerID) peer.On("Send", mock.Anything, mock.Anything).Run(func(args mock.Arguments) { peerID := args.Get(0).(p2ptypes.PeerID) @@ -189,9 +189,9 @@ func TestDispatcher_RespondWithError(t *testing.T) { require.NoError(t, dispatcher.Start(ctx)) // unknown capability - recvCh <- encodeAndSign(t, privKey1, peerId1, peerId2, capId1, donId1, []byte(payload1)) + recvCh <- encodeAndSign(t, privKey1, peerID1, peerID2, capID1, donID1, []byte(payload1)) responseDestPeerID := <-sendCh - require.Equal(t, peerId1, responseDestPeerID) + require.Equal(t, peerID1, responseDestPeerID) require.NoError(t, dispatcher.Close()) } diff --git a/core/capabilities/remote/executable/endtoend_test.go b/core/capabilities/remote/executable/endtoend_test.go index 5f445db4235..886bde9d33d 100644 --- a/core/capabilities/remote/executable/endtoend_test.go +++ b/core/capabilities/remote/executable/endtoend_test.go @@ -224,9 +224,9 @@ func (a *testAsyncMessageBroker) start(ctx context.Context) error { case <-ctx.Done(): return case msg := <-a.sendCh: - receiverId := toPeerID(msg.Receiver) + receiverID := toPeerID(msg.Receiver) - receiver, ok := a.nodes[receiverId] + receiver, ok := a.nodes[receiverID] if !ok { panic("server not found for peer id") } @@ -299,10 +299,10 @@ func (t *nodeDispatcher) Send(peerID p2ptypes.PeerID, msgBody *remotetypes.Messa return nil } -func (t *nodeDispatcher) SetReceiver(capabilityId string, donId uint32, receiver remotetypes.Receiver) error { +func (t *nodeDispatcher) SetReceiver(capabilityID string, donID uint32, receiver remotetypes.Receiver) error { return nil } -func (t *nodeDispatcher) RemoveReceiver(capabilityId string, donId uint32) {} +func (t *nodeDispatcher) RemoveReceiver(capabilityID string, donID uint32) {} type abstractTestCapability struct { } @@ -407,29 +407,3 @@ func executeCapability(ctx context.Context, t *testing.T, caller commoncap.Execu responseTest(t, response, err) } - -func registerWorkflow(ctx context.Context, t *testing.T, caller commoncap.ExecutableCapability, transmissionSchedule *values.Map, responseTest func(t *testing.T, responseError error)) { - err := caller.RegisterToWorkflow(ctx, commoncap.RegisterToWorkflowRequest{ - Metadata: commoncap.RegistrationMetadata{ - WorkflowID: workflowID1, - ReferenceID: stepReferenceID1, - WorkflowOwner: workflowOwnerID, - }, - Config: transmissionSchedule, - }) - - responseTest(t, err) -} - -func unregisterWorkflow(ctx context.Context, t *testing.T, caller commoncap.ExecutableCapability, transmissionSchedule *values.Map, responseTest func(t *testing.T, responseError error)) { - err := caller.UnregisterFromWorkflow(ctx, commoncap.UnregisterFromWorkflowRequest{ - Metadata: commoncap.RegistrationMetadata{ - WorkflowID: workflowID1, - ReferenceID: stepReferenceID1, - WorkflowOwner: workflowOwnerID, - }, - Config: transmissionSchedule, - }) - - responseTest(t, err) -} diff --git a/core/capabilities/remote/executable/request/client_request.go b/core/capabilities/remote/executable/request/client_request.go index 6b4b9e3a0cd..ef4d0023773 100644 --- a/core/capabilities/remote/executable/request/client_request.go +++ b/core/capabilities/remote/executable/request/client_request.go @@ -212,7 +212,7 @@ func (c *ClientRequest) OnMessage(_ context.Context, msg *types.MessageBody) err } if msg.Sender == nil { - return fmt.Errorf("sender missing from message") + return errors.New("sender missing from message") } c.lggr.Debugw("OnMessage called for client request", "messageID", msg.MessageId) diff --git a/core/capabilities/remote/executable/request/client_request_test.go b/core/capabilities/remote/executable/request/client_request_test.go index c46fd1363a0..45e81fc70d8 100644 --- a/core/capabilities/remote/executable/request/client_request_test.go +++ b/core/capabilities/remote/executable/request/client_request_test.go @@ -167,7 +167,7 @@ func Test_ClientRequest_MessageValidation(t *testing.T) { nonDonPeer := NewP2PPeerID(t) msg.Sender = nonDonPeer[:] err = request.OnMessage(ctx, msg) - require.NotNil(t, err) + require.Error(t, err) select { case <-request.ResponseChan(): @@ -190,7 +190,7 @@ func Test_ClientRequest_MessageValidation(t *testing.T) { err = request.OnMessage(ctx, msg) require.NoError(t, err) err = request.OnMessage(ctx, msg) - require.NotNil(t, err) + require.Error(t, err) select { case <-request.ResponseChan(): @@ -211,7 +211,7 @@ func Test_ClientRequest_MessageValidation(t *testing.T) { <-dispatcher.msgs <-dispatcher.msgs - assert.Equal(t, 0, len(dispatcher.msgs)) + assert.Empty(t, dispatcher.msgs) msgWithError := &types.MessageBody{ CapabilityId: capInfo.ID, @@ -249,7 +249,7 @@ func Test_ClientRequest_MessageValidation(t *testing.T) { <-dispatcher.msgs <-dispatcher.msgs - assert.Equal(t, 0, len(dispatcher.msgs)) + assert.Empty(t, dispatcher.msgs) msgWithError := &types.MessageBody{ CapabilityId: capInfo.ID, @@ -299,7 +299,7 @@ func Test_ClientRequest_MessageValidation(t *testing.T) { <-dispatcher.msgs <-dispatcher.msgs - assert.Equal(t, 0, len(dispatcher.msgs)) + assert.Empty(t, dispatcher.msgs) msg.Sender = capabilityPeers[0][:] err = request.OnMessage(ctx, msg) @@ -497,11 +497,11 @@ func (t *clientRequestTestDispatcher) HealthReport() map[string]error { return nil } -func (t *clientRequestTestDispatcher) SetReceiver(capabilityId string, donId uint32, receiver types.Receiver) error { +func (t *clientRequestTestDispatcher) SetReceiver(capabilityID string, donID uint32, receiver types.Receiver) error { return nil } -func (t *clientRequestTestDispatcher) RemoveReceiver(capabilityId string, donId uint32) {} +func (t *clientRequestTestDispatcher) RemoveReceiver(capabilityID string, donID uint32) {} func (t *clientRequestTestDispatcher) Send(peerID p2ptypes.PeerID, msgBody *types.MessageBody) error { t.msgs <- msgBody diff --git a/core/capabilities/remote/executable/request/server_request.go b/core/capabilities/remote/executable/request/server_request.go index 629622494a4..ee4e48fe1b9 100644 --- a/core/capabilities/remote/executable/request/server_request.go +++ b/core/capabilities/remote/executable/request/server_request.go @@ -26,7 +26,7 @@ type response struct { type ServerRequest struct { capability capabilities.ExecutableCapability - capabilityPeerId p2ptypes.PeerID + capabilityPeerID p2ptypes.PeerID capabilityID string capabilityDonID uint32 @@ -60,7 +60,7 @@ func NewServerRequest(capability capabilities.ExecutableCapability, method strin createdTime: time.Now(), capabilityID: capabilityID, capabilityDonID: capabilityDonID, - capabilityPeerId: capabilityPeerID, + capabilityPeerID: capabilityPeerID, dispatcher: dispatcher, requesters: map[p2ptypes.PeerID]bool{}, responseSentToRequester: map[p2ptypes.PeerID]bool{}, @@ -77,7 +77,7 @@ func (e *ServerRequest) OnMessage(ctx context.Context, msg *types.MessageBody) e defer e.mux.Unlock() if msg.Sender == nil { - return fmt.Errorf("sender missing from message") + return errors.New("sender missing from message") } requester, err := remote.ToPeerID(msg.Sender) @@ -206,7 +206,7 @@ func (e *ServerRequest) sendResponse(requester p2ptypes.PeerID) error { CallerDonId: e.callingDon.ID, Method: types.MethodExecute, MessageId: []byte(e.requestMessageID), - Sender: e.capabilityPeerId[:], + Sender: e.capabilityPeerID[:], Receiver: requester[:], } diff --git a/core/capabilities/remote/executable/request/server_request_test.go b/core/capabilities/remote/executable/request/server_request_test.go index ce539154d93..faf91be0690 100644 --- a/core/capabilities/remote/executable/request/server_request_test.go +++ b/core/capabilities/remote/executable/request/server_request_test.go @@ -311,11 +311,11 @@ func (t *testDispatcher) HealthReport() map[string]error { return nil } -func (t *testDispatcher) SetReceiver(capabilityId string, donId uint32, receiver types.Receiver) error { +func (t *testDispatcher) SetReceiver(capabilityID string, donID uint32, receiver types.Receiver) error { return nil } -func (t *testDispatcher) RemoveReceiver(capabilityId string, donId uint32) {} +func (t *testDispatcher) RemoveReceiver(capabilityID string, donID uint32) {} func (t *testDispatcher) Send(peerID p2ptypes.PeerID, msgBody *types.MessageBody) error { t.msgs = append(t.msgs, msgBody) diff --git a/core/capabilities/remote/executable/server.go b/core/capabilities/remote/executable/server.go index d43c7ab5c41..0208572b0bd 100644 --- a/core/capabilities/remote/executable/server.go +++ b/core/capabilities/remote/executable/server.go @@ -4,6 +4,7 @@ import ( "context" "crypto/sha256" "encoding/hex" + "errors" "fmt" "sync" "time" @@ -142,7 +143,7 @@ func (r *server) Receive(ctx context.Context, msg *types.MessageBody) { r.lggr.Errorw("received request for unsupported method type", "method", remote.SanitizeLogString(msg.Method)) } - messageId, err := GetMessageID(msg) + messageID, err := GetMessageID(msg) if err != nil { r.lggr.Errorw("invalid message id", "err", err, "id", remote.SanitizeLogString(string(msg.MessageId))) return @@ -156,21 +157,21 @@ func (r *server) Receive(ctx context.Context, msg *types.MessageBody) { // A request is uniquely identified by the message id and the hash of the payload to prevent a malicious // actor from sending a different payload with the same message id - requestID := messageId + hex.EncodeToString(msgHash[:]) + requestID := messageID + hex.EncodeToString(msgHash[:]) r.lggr.Debugw("received request", "msgId", msg.MessageId, "requestID", requestID) - if requestIDs, ok := r.messageIDToRequestIDsCount[messageId]; ok { - requestIDs[requestID] = requestIDs[requestID] + 1 + if requestIDs, ok := r.messageIDToRequestIDsCount[messageID]; ok { + requestIDs[requestID]++ } else { - r.messageIDToRequestIDsCount[messageId] = map[string]int{requestID: 1} + r.messageIDToRequestIDsCount[messageID] = map[string]int{requestID: 1} } - requestIDs := r.messageIDToRequestIDsCount[messageId] + requestIDs := r.messageIDToRequestIDsCount[messageID] if len(requestIDs) > 1 { // This is a potential attack vector as well as a situation that will occur if the client is sending non-deterministic payloads // so a warning is logged - r.lggr.Warnw("received messages with the same id and different payloads", "messageID", messageId, "lenRequestIDs", len(requestIDs)) + r.lggr.Warnw("received messages with the same id and different payloads", "messageID", messageID, "lenRequestIDs", len(requestIDs)) } if _, ok := r.requestIDToRequest[requestID]; !ok { @@ -182,8 +183,8 @@ func (r *server) Receive(ctx context.Context, msg *types.MessageBody) { r.requestIDToRequest[requestID] = requestAndMsgID{ request: request.NewServerRequest(r.underlying, msg.Method, r.capInfo.ID, r.localDonInfo.ID, r.peerID, - callingDon, messageId, r.dispatcher, r.requestTimeout, r.lggr), - messageID: messageId, + callingDon, messageID, r.dispatcher, r.requestTimeout, r.lggr), + messageID: messageID, } } @@ -218,7 +219,7 @@ func (r *server) getMessageHash(msg *types.MessageBody) ([32]byte, error) { func GetMessageID(msg *types.MessageBody) (string, error) { idStr := string(msg.MessageId) if !validation.IsValidID(idStr) { - return "", fmt.Errorf("invalid message id") + return "", errors.New("invalid message id") } return idStr, nil } diff --git a/core/capabilities/remote/message_cache.go b/core/capabilities/remote/messagecache/message_cache.go similarity index 81% rename from core/capabilities/remote/message_cache.go rename to core/capabilities/remote/messagecache/message_cache.go index f3a3a79b2c6..28ef57ab875 100644 --- a/core/capabilities/remote/message_cache.go +++ b/core/capabilities/remote/messagecache/message_cache.go @@ -1,9 +1,9 @@ -package remote +package messagecache // MessageCache is a simple store for messages, grouped by event ID and peer ID. // It is used to collect messages from multiple peers until they are ready for aggregation // based on quantity and freshness. -type messageCache[EventID comparable, PeerID comparable] struct { +type MessageCache[EventID comparable, PeerID comparable] struct { events map[EventID]*eventState[PeerID] } @@ -18,14 +18,14 @@ type msgState struct { payload []byte } -func NewMessageCache[EventID comparable, PeerID comparable]() *messageCache[EventID, PeerID] { - return &messageCache[EventID, PeerID]{ +func NewMessageCache[EventID comparable, PeerID comparable]() *MessageCache[EventID, PeerID] { + return &MessageCache[EventID, PeerID]{ events: make(map[EventID]*eventState[PeerID]), } } // Insert or overwrite a message for . Return creation timestamp of the event. -func (c *messageCache[EventID, PeerID]) Insert(eventID EventID, peerID PeerID, timestamp int64, payload []byte) int64 { +func (c *MessageCache[EventID, PeerID]) Insert(eventID EventID, peerID PeerID, timestamp int64, payload []byte) int64 { if _, ok := c.events[eventID]; !ok { c.events[eventID] = &eventState[PeerID]{ peerMsgs: make(map[PeerID]*msgState), @@ -43,7 +43,7 @@ func (c *messageCache[EventID, PeerID]) Insert(eventID EventID, peerID PeerID, t // received more recently than . // Return all messages that satisfy the above condition. // Ready() will return true at most once per event if is true. -func (c *messageCache[EventID, PeerID]) Ready(eventID EventID, minCount uint32, minTimestamp int64, once bool) (bool, [][]byte) { +func (c *MessageCache[EventID, PeerID]) Ready(eventID EventID, minCount uint32, minTimestamp int64, once bool) (bool, [][]byte) { ev, ok := c.events[eventID] if !ok { return false, nil @@ -51,6 +51,7 @@ func (c *messageCache[EventID, PeerID]) Ready(eventID EventID, minCount uint32, if ev.wasReady && once { return false, nil } + //nolint:gosec // G115 if uint32(len(ev.peerMsgs)) < minCount { return false, nil } @@ -69,13 +70,13 @@ func (c *messageCache[EventID, PeerID]) Ready(eventID EventID, minCount uint32, return false, nil } -func (c *messageCache[EventID, PeerID]) Delete(eventID EventID) { +func (c *MessageCache[EventID, PeerID]) Delete(eventID EventID) { delete(c.events, eventID) } // Return the number of events deleted. // Scans all keys, which might be slow for large caches. -func (c *messageCache[EventID, PeerID]) DeleteOlderThan(cutoffTimestamp int64) int { +func (c *MessageCache[EventID, PeerID]) DeleteOlderThan(cutoffTimestamp int64) int { nDeleted := 0 for id, event := range c.events { if event.creationTimestamp < cutoffTimestamp { diff --git a/core/capabilities/remote/message_cache_test.go b/core/capabilities/remote/messagecache/message_cache_test.go similarity index 59% rename from core/capabilities/remote/message_cache_test.go rename to core/capabilities/remote/messagecache/message_cache_test.go index 5ca909ca4ec..2d059adef32 100644 --- a/core/capabilities/remote/message_cache_test.go +++ b/core/capabilities/remote/messagecache/message_cache_test.go @@ -1,53 +1,53 @@ -package remote_test +package messagecache_test import ( "testing" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/messagecache" ) const ( - eventId1 = "event1" - eventId2 = "event2" - peerId1 = "peer1" - peerId2 = "peer2" + eventID1 = "event1" + eventID2 = "event2" + peerID1 = "peer1" + peerID2 = "peer2" payloadA = "payloadA" ) func TestMessageCache_InsertReady(t *testing.T) { - cache := remote.NewMessageCache[string, string]() + cache := messagecache.NewMessageCache[string, string]() // not ready with one message - ts := cache.Insert(eventId1, peerId1, 100, []byte(payloadA)) + ts := cache.Insert(eventID1, peerID1, 100, []byte(payloadA)) require.Equal(t, int64(100), ts) - ready, _ := cache.Ready(eventId1, 2, 100, true) + ready, _ := cache.Ready(eventID1, 2, 100, true) require.False(t, ready) // not ready with two messages but only one fresh enough - ts = cache.Insert(eventId1, peerId2, 200, []byte(payloadA)) + ts = cache.Insert(eventID1, peerID2, 200, []byte(payloadA)) require.Equal(t, int64(100), ts) - ready, _ = cache.Ready(eventId1, 2, 150, true) + ready, _ = cache.Ready(eventID1, 2, 150, true) require.False(t, ready) // ready with two messages (once only) - ready, messages := cache.Ready(eventId1, 2, 100, true) + ready, messages := cache.Ready(eventID1, 2, 100, true) require.True(t, ready) require.Equal(t, []byte(payloadA), messages[0]) require.Equal(t, []byte(payloadA), messages[1]) // not ready again for the same event ID - ready, _ = cache.Ready(eventId1, 2, 100, true) + ready, _ = cache.Ready(eventID1, 2, 100, true) require.False(t, ready) } func TestMessageCache_DeleteOlderThan(t *testing.T) { - cache := remote.NewMessageCache[string, string]() + cache := messagecache.NewMessageCache[string, string]() - ts := cache.Insert(eventId1, peerId1, 100, []byte(payloadA)) + ts := cache.Insert(eventID1, peerID1, 100, []byte(payloadA)) require.Equal(t, int64(100), ts) - ts = cache.Insert(eventId2, peerId2, 200, []byte(payloadA)) + ts = cache.Insert(eventID2, peerID2, 200, []byte(payloadA)) require.Equal(t, int64(200), ts) deleted := cache.DeleteOlderThan(150) diff --git a/core/capabilities/remote/trigger_publisher.go b/core/capabilities/remote/trigger_publisher.go index 315959605e8..24bd26757ac 100644 --- a/core/capabilities/remote/trigger_publisher.go +++ b/core/capabilities/remote/trigger_publisher.go @@ -10,6 +10,8 @@ import ( commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/aggregation" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/messagecache" "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" "github.com/smartcontractkit/chainlink/v2/core/capabilities/validation" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -30,7 +32,7 @@ type triggerPublisher struct { workflowDONs map[uint32]commoncap.DON membersCache map[uint32]map[p2ptypes.PeerID]bool dispatcher types.Dispatcher - messageCache *messageCache[registrationKey, p2ptypes.PeerID] + messageCache *messagecache.MessageCache[registrationKey, p2ptypes.PeerID] registrations map[registrationKey]*pubRegState mu sync.RWMutex // protects messageCache and registrations batchingQueue map[[32]byte]*batchedResponse @@ -42,8 +44,8 @@ type triggerPublisher struct { } type registrationKey struct { - callerDonId uint32 - workflowId string + callerDonID uint32 + workflowID string } type pubRegState struct { @@ -84,7 +86,7 @@ func NewTriggerPublisher(config *commoncap.RemoteTriggerConfig, underlying commo workflowDONs: workflowDONs, membersCache: membersCache, dispatcher: dispatcher, - messageCache: NewMessageCache[registrationKey, p2ptypes.PeerID](), + messageCache: messagecache.NewMessageCache[registrationKey, p2ptypes.PeerID](), registrations: make(map[registrationKey]*pubRegState), batchingQueue: make(map[[32]byte]*batchedResponse), batchingEnabled: config.MaxBatchSize > 1 && config.BatchCollectionPeriod >= minAllowedBatchCollectionPeriod, @@ -148,7 +150,7 @@ func (p *triggerPublisher) Receive(_ context.Context, msg *types.MessageBody) { p.lggr.Debugw("not ready to aggregate yet", "capabilityId", p.capInfo.ID, "workflowId", req.Metadata.WorkflowID, "minRequired", minRequired) return } - aggregated, err := AggregateModeRaw(payloads, uint32(callerDon.F+1)) + aggregated, err := aggregation.AggregateModeRaw(payloads, uint32(callerDon.F+1)) if err != nil { p.lggr.Errorw("failed to aggregate trigger registrations", "capabilityId", p.capInfo.ID, "workflowId", req.Metadata.WorkflowID, "err", err) return @@ -189,14 +191,14 @@ func (p *triggerPublisher) registrationCleanupLoop() { now := time.Now().UnixMilli() p.mu.Lock() for key, req := range p.registrations { - callerDon := p.workflowDONs[key.callerDonId] + callerDon := p.workflowDONs[key.callerDonID] ready, _ := p.messageCache.Ready(key, uint32(2*callerDon.F+1), now-p.config.RegistrationExpiry.Milliseconds(), false) if !ready { - p.lggr.Infow("trigger registration expired", "capabilityId", p.capInfo.ID, "callerDonID", key.callerDonId, "workflowId", key.workflowId) + p.lggr.Infow("trigger registration expired", "capabilityId", p.capInfo.ID, "callerDonID", key.callerDonID, "workflowId", key.workflowID) ctx, cancel := p.stopCh.NewCtx() err := p.underlying.UnregisterTrigger(ctx, req.request) cancel() - p.lggr.Infow("unregistered trigger", "capabilityId", p.capInfo.ID, "callerDonID", key.callerDonId, "workflowId", key.workflowId, "err", err) + p.lggr.Infow("unregistered trigger", "capabilityId", p.capInfo.ID, "callerDonID", key.callerDonID, "workflowId", key.workflowID, "err", err) // after calling UnregisterTrigger, the underlying trigger will not send any more events to the channel delete(p.registrations, key) p.messageCache.Delete(key) @@ -215,11 +217,11 @@ func (p *triggerPublisher) triggerEventLoop(callbackCh <-chan commoncap.TriggerR return case response, ok := <-callbackCh: if !ok { - p.lggr.Infow("triggerEventLoop channel closed", "capabilityId", p.capInfo.ID, "workflowId", key.workflowId) + p.lggr.Infow("triggerEventLoop channel closed", "capabilityId", p.capInfo.ID, "workflowId", key.workflowID) return } triggerEvent := response.Event - p.lggr.Debugw("received trigger event", "capabilityId", p.capInfo.ID, "workflowId", key.workflowId, "triggerEventID", triggerEvent.ID) + p.lggr.Debugw("received trigger event", "capabilityId", p.capInfo.ID, "workflowId", key.workflowID, "triggerEventID", triggerEvent.ID) marshaledResponse, err := pb.MarshalTriggerResponse(response) if err != nil { p.lggr.Debugw("can't marshal trigger event", "err", err) @@ -232,9 +234,9 @@ func (p *triggerPublisher) triggerEventLoop(callbackCh <-chan commoncap.TriggerR // a single-element "batch" p.sendBatch(&batchedResponse{ rawResponse: marshaledResponse, - callerDonID: key.callerDonId, + callerDonID: key.callerDonID, triggerEventID: triggerEvent.ID, - workflowIDs: []string{key.workflowId}, + workflowIDs: []string{key.workflowID}, }) } } @@ -244,7 +246,7 @@ func (p *triggerPublisher) triggerEventLoop(callbackCh <-chan commoncap.TriggerR func (p *triggerPublisher) enqueueForBatching(rawResponse []byte, key registrationKey, triggerEventID string) { // put in batching queue, group by hash(callerDonId, triggerEventID, response) combined := make([]byte, 4) - binary.LittleEndian.PutUint32(combined, key.callerDonId) + binary.LittleEndian.PutUint32(combined, key.callerDonID) combined = append(combined, []byte(triggerEventID)...) combined = append(combined, rawResponse...) sha := sha256.Sum256(combined) @@ -253,13 +255,13 @@ func (p *triggerPublisher) enqueueForBatching(rawResponse []byte, key registrati if !exists { elem = &batchedResponse{ rawResponse: rawResponse, - callerDonID: key.callerDonId, + callerDonID: key.callerDonID, triggerEventID: triggerEventID, - workflowIDs: []string{key.workflowId}, + workflowIDs: []string{key.workflowID}, } p.batchingQueue[sha] = elem } else { - elem.workflowIDs = append(elem.workflowIDs, key.workflowId) + elem.workflowIDs = append(elem.workflowIDs, key.workflowID) } p.bqMu.Unlock() } diff --git a/core/capabilities/remote/trigger_subscriber.go b/core/capabilities/remote/trigger_subscriber.go index 2638d9ca5f3..7edcbf5eba7 100644 --- a/core/capabilities/remote/trigger_subscriber.go +++ b/core/capabilities/remote/trigger_subscriber.go @@ -9,6 +9,8 @@ import ( commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/aggregation" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/messagecache" "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" "github.com/smartcontractkit/chainlink/v2/core/logger" p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" @@ -29,7 +31,7 @@ type triggerSubscriber struct { localDonInfo commoncap.DON dispatcher types.Dispatcher aggregator types.Aggregator - messageCache *messageCache[triggerEventKey, p2ptypes.PeerID] + messageCache *messagecache.MessageCache[triggerEventKey, p2ptypes.PeerID] registeredWorkflows map[string]*subRegState mu sync.RWMutex // protects registeredWorkflows and messageCache stopCh services.StopChan @@ -38,8 +40,8 @@ type triggerSubscriber struct { } type triggerEventKey struct { - triggerEventId string - workflowId string + triggerEventID string + workflowID string } type subRegState struct { @@ -65,7 +67,7 @@ const ( func NewTriggerSubscriber(config *commoncap.RemoteTriggerConfig, capInfo commoncap.CapabilityInfo, capDonInfo commoncap.DON, localDonInfo commoncap.DON, dispatcher types.Dispatcher, aggregator types.Aggregator, lggr logger.Logger) *triggerSubscriber { if aggregator == nil { lggr.Warnw("no aggregator provided, using default MODE aggregator", "capabilityId", capInfo.ID) - aggregator = NewDefaultModeAggregator(uint32(capDonInfo.F + 1)) + aggregator = aggregation.NewDefaultModeAggregator(uint32(capDonInfo.F + 1)) } if config == nil { lggr.Info("no config provided, using default values") @@ -84,7 +86,7 @@ func NewTriggerSubscriber(config *commoncap.RemoteTriggerConfig, capInfo commonc localDonInfo: localDonInfo, dispatcher: dispatcher, aggregator: aggregator, - messageCache: NewMessageCache[triggerEventKey, p2ptypes.PeerID](), + messageCache: messagecache.NewMessageCache[triggerEventKey, p2ptypes.PeerID](), registeredWorkflows: make(map[string]*subRegState), stopCh: make(services.StopChan), lggr: lggr.Named("TriggerSubscriber"), @@ -200,17 +202,17 @@ func (s *triggerSubscriber) Receive(_ context.Context, msg *types.MessageBody) { s.lggr.Errorw("received message with too many workflow IDs - truncating", "capabilityId", s.capInfo.ID, "nWorkflows", len(meta.WorkflowIds), "sender", sender) meta.WorkflowIds = meta.WorkflowIds[:maxBatchedWorkflowIDs] } - for _, workflowId := range meta.WorkflowIds { + for _, workflowID := range meta.WorkflowIds { s.mu.RLock() - registration, found := s.registeredWorkflows[workflowId] + registration, found := s.registeredWorkflows[workflowID] s.mu.RUnlock() if !found { - s.lggr.Errorw("received message for unregistered workflow", "capabilityId", s.capInfo.ID, "workflowID", SanitizeLogString(workflowId), "sender", sender) + s.lggr.Errorw("received message for unregistered workflow", "capabilityId", s.capInfo.ID, "workflowID", SanitizeLogString(workflowID), "sender", sender) continue } key := triggerEventKey{ - triggerEventId: meta.TriggerEventId, - workflowId: workflowId, + triggerEventID: meta.TriggerEventId, + workflowID: workflowID, } nowMs := time.Now().UnixMilli() s.mu.Lock() @@ -218,17 +220,17 @@ func (s *triggerSubscriber) Receive(_ context.Context, msg *types.MessageBody) { ready, payloads := s.messageCache.Ready(key, s.config.MinResponsesToAggregate, nowMs-s.config.MessageExpiry.Milliseconds(), true) s.mu.Unlock() if nowMs-creationTs > s.config.RegistrationExpiry.Milliseconds() { - s.lggr.Warnw("received trigger event for an expired ID", "triggerEventID", meta.TriggerEventId, "capabilityId", s.capInfo.ID, "workflowId", workflowId, "sender", sender) + s.lggr.Warnw("received trigger event for an expired ID", "triggerEventID", meta.TriggerEventId, "capabilityId", s.capInfo.ID, "workflowId", workflowID, "sender", sender) continue } if ready { - s.lggr.Debugw("trigger event ready to aggregate", "triggerEventID", meta.TriggerEventId, "capabilityId", s.capInfo.ID, "workflowId", workflowId) + s.lggr.Debugw("trigger event ready to aggregate", "triggerEventID", meta.TriggerEventId, "capabilityId", s.capInfo.ID, "workflowId", workflowID) aggregatedResponse, err := s.aggregator.Aggregate(meta.TriggerEventId, payloads) if err != nil { - s.lggr.Errorw("failed to aggregate responses", "triggerEventID", meta.TriggerEventId, "capabilityId", s.capInfo.ID, "workflowId", workflowId, "err", err) + s.lggr.Errorw("failed to aggregate responses", "triggerEventID", meta.TriggerEventId, "capabilityId", s.capInfo.ID, "workflowId", workflowID, "err", err) continue } - s.lggr.Infow("remote trigger event aggregated", "triggerEventID", meta.TriggerEventId, "capabilityId", s.capInfo.ID, "workflowId", workflowId) + s.lggr.Infow("remote trigger event aggregated", "triggerEventID", meta.TriggerEventId, "capabilityId", s.capInfo.ID, "workflowId", workflowID) registration.callback <- aggregatedResponse } } diff --git a/core/capabilities/remote/trigger_subscriber_test.go b/core/capabilities/remote/trigger_subscriber_test.go index b8cc3ddc7bd..d5b48bc1dc8 100644 --- a/core/capabilities/remote/trigger_subscriber_test.go +++ b/core/capabilities/remote/trigger_subscriber_test.go @@ -26,7 +26,6 @@ const ( var ( triggerEvent1 = map[string]any{"event": "triggerEvent1"} - triggerEvent2 = map[string]any{"event": "triggerEvent2"} ) func TestTriggerSubscriber_RegisterAndReceive(t *testing.T) { diff --git a/core/capabilities/remote/types/mocks/dispatcher.go b/core/capabilities/remote/types/mocks/dispatcher.go index 0948698b935..d7f2ab45bac 100644 --- a/core/capabilities/remote/types/mocks/dispatcher.go +++ b/core/capabilities/remote/types/mocks/dispatcher.go @@ -206,9 +206,9 @@ func (_c *Dispatcher_Ready_Call) RunAndReturn(run func() error) *Dispatcher_Read return _c } -// RemoveReceiver provides a mock function with given fields: capabilityId, donId -func (_m *Dispatcher) RemoveReceiver(capabilityId string, donId uint32) { - _m.Called(capabilityId, donId) +// RemoveReceiver provides a mock function with given fields: capabilityID, donID +func (_m *Dispatcher) RemoveReceiver(capabilityID string, donID uint32) { + _m.Called(capabilityID, donID) } // Dispatcher_RemoveReceiver_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveReceiver' @@ -217,13 +217,13 @@ type Dispatcher_RemoveReceiver_Call struct { } // RemoveReceiver is a helper method to define mock.On call -// - capabilityId string -// - donId uint32 -func (_e *Dispatcher_Expecter) RemoveReceiver(capabilityId interface{}, donId interface{}) *Dispatcher_RemoveReceiver_Call { - return &Dispatcher_RemoveReceiver_Call{Call: _e.mock.On("RemoveReceiver", capabilityId, donId)} +// - capabilityID string +// - donID uint32 +func (_e *Dispatcher_Expecter) RemoveReceiver(capabilityID interface{}, donID interface{}) *Dispatcher_RemoveReceiver_Call { + return &Dispatcher_RemoveReceiver_Call{Call: _e.mock.On("RemoveReceiver", capabilityID, donID)} } -func (_c *Dispatcher_RemoveReceiver_Call) Run(run func(capabilityId string, donId uint32)) *Dispatcher_RemoveReceiver_Call { +func (_c *Dispatcher_RemoveReceiver_Call) Run(run func(capabilityID string, donID uint32)) *Dispatcher_RemoveReceiver_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(string), args[1].(uint32)) }) @@ -287,9 +287,9 @@ func (_c *Dispatcher_Send_Call) RunAndReturn(run func(p2ptypes.PeerID, *types.Me return _c } -// SetReceiver provides a mock function with given fields: capabilityId, donId, receiver -func (_m *Dispatcher) SetReceiver(capabilityId string, donId uint32, receiver types.Receiver) error { - ret := _m.Called(capabilityId, donId, receiver) +// SetReceiver provides a mock function with given fields: capabilityID, donID, receiver +func (_m *Dispatcher) SetReceiver(capabilityID string, donID uint32, receiver types.Receiver) error { + ret := _m.Called(capabilityID, donID, receiver) if len(ret) == 0 { panic("no return value specified for SetReceiver") @@ -297,7 +297,7 @@ func (_m *Dispatcher) SetReceiver(capabilityId string, donId uint32, receiver ty var r0 error if rf, ok := ret.Get(0).(func(string, uint32, types.Receiver) error); ok { - r0 = rf(capabilityId, donId, receiver) + r0 = rf(capabilityID, donID, receiver) } else { r0 = ret.Error(0) } @@ -311,14 +311,14 @@ type Dispatcher_SetReceiver_Call struct { } // SetReceiver is a helper method to define mock.On call -// - capabilityId string -// - donId uint32 +// - capabilityID string +// - donID uint32 // - receiver types.Receiver -func (_e *Dispatcher_Expecter) SetReceiver(capabilityId interface{}, donId interface{}, receiver interface{}) *Dispatcher_SetReceiver_Call { - return &Dispatcher_SetReceiver_Call{Call: _e.mock.On("SetReceiver", capabilityId, donId, receiver)} +func (_e *Dispatcher_Expecter) SetReceiver(capabilityID interface{}, donID interface{}, receiver interface{}) *Dispatcher_SetReceiver_Call { + return &Dispatcher_SetReceiver_Call{Call: _e.mock.On("SetReceiver", capabilityID, donID, receiver)} } -func (_c *Dispatcher_SetReceiver_Call) Run(run func(capabilityId string, donId uint32, receiver types.Receiver)) *Dispatcher_SetReceiver_Call { +func (_c *Dispatcher_SetReceiver_Call) Run(run func(capabilityID string, donID uint32, receiver types.Receiver)) *Dispatcher_SetReceiver_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(string), args[1].(uint32), args[2].(types.Receiver)) }) diff --git a/core/capabilities/remote/types/types.go b/core/capabilities/remote/types/types.go index fefc9a9b5fe..188587bc7ac 100644 --- a/core/capabilities/remote/types/types.go +++ b/core/capabilities/remote/types/types.go @@ -23,8 +23,8 @@ const ( type Dispatcher interface { services.Service - SetReceiver(capabilityId string, donId uint32, receiver Receiver) error - RemoveReceiver(capabilityId string, donId uint32) + SetReceiver(capabilityID string, donID uint32, receiver Receiver) error + RemoveReceiver(capabilityID string, donID uint32) Send(peerID p2ptypes.PeerID, msgBody *MessageBody) error } diff --git a/core/capabilities/remote/utils.go b/core/capabilities/remote/utils.go index ea6a3efb186..7af34c5c946 100644 --- a/core/capabilities/remote/utils.go +++ b/core/capabilities/remote/utils.go @@ -3,7 +3,6 @@ package remote import ( "bytes" "crypto/ed25519" - "crypto/sha256" "encoding/hex" "errors" "fmt" @@ -11,8 +10,6 @@ import ( "google.golang.org/protobuf/proto" - commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" - "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" ) @@ -25,25 +22,25 @@ func ValidateMessage(msg p2ptypes.Message, expectedReceiver p2ptypes.PeerID) (*r var topLevelMessage remotetypes.Message err := proto.Unmarshal(msg.Payload, &topLevelMessage) if err != nil { - return nil, fmt.Errorf("failed to unmarshal message, err: %v", err) + return nil, fmt.Errorf("failed to unmarshal message, err: %w", err) } var body remotetypes.MessageBody err = proto.Unmarshal(topLevelMessage.Body, &body) if err != nil { - return nil, fmt.Errorf("failed to unmarshal message body, err: %v", err) + return nil, fmt.Errorf("failed to unmarshal message body, err: %w", err) } if len(body.Sender) != p2ptypes.PeerIDLength || len(body.Receiver) != p2ptypes.PeerIDLength { return &body, fmt.Errorf("invalid sender length (%d) or receiver length (%d)", len(body.Sender), len(body.Receiver)) } if !ed25519.Verify(body.Sender, topLevelMessage.Body, topLevelMessage.Signature) { - return &body, fmt.Errorf("failed to verify message signature") + return &body, errors.New("failed to verify message signature") } // NOTE we currently don't support relaying messages so the p2p message sender needs to be the message author if !bytes.Equal(body.Sender, msg.Sender[:]) { - return &body, fmt.Errorf("sender in message body does not match sender of p2p message") + return &body, errors.New("sender in message body does not match sender of p2p message") } if !bytes.Equal(body.Receiver, expectedReceiver[:]) { - return &body, fmt.Errorf("receiver in message body does not match expected receiver") + return &body, errors.New("receiver in message body does not match expected receiver") } return &body, nil } @@ -58,52 +55,6 @@ func ToPeerID(peerID []byte) (p2ptypes.PeerID, error) { return id, nil } -// Default MODE Aggregator needs a configurable number of identical responses for aggregation to succeed -type defaultModeAggregator struct { - minIdenticalResponses uint32 -} - -var _ remotetypes.Aggregator = &defaultModeAggregator{} - -func NewDefaultModeAggregator(minIdenticalResponses uint32) *defaultModeAggregator { - return &defaultModeAggregator{ - minIdenticalResponses: minIdenticalResponses, - } -} - -func (a *defaultModeAggregator) Aggregate(_ string, responses [][]byte) (commoncap.TriggerResponse, error) { - found, err := AggregateModeRaw(responses, a.minIdenticalResponses) - if err != nil { - return commoncap.TriggerResponse{}, fmt.Errorf("failed to aggregate responses, err: %w", err) - } - - unmarshaled, err := pb.UnmarshalTriggerResponse(found) - if err != nil { - return commoncap.TriggerResponse{}, fmt.Errorf("failed to unmarshal aggregated responses, err: %w", err) - } - return unmarshaled, nil -} - -func AggregateModeRaw(elemList [][]byte, minIdenticalResponses uint32) ([]byte, error) { - hashToCount := make(map[string]uint32) - var found []byte - for _, elem := range elemList { - hasher := sha256.New() - hasher.Write(elem) - sha := hex.EncodeToString(hasher.Sum(nil)) - hashToCount[sha]++ - if hashToCount[sha] >= minIdenticalResponses { - found = elem - // update in case we find another elem with an even higher count - minIdenticalResponses = hashToCount[sha] - } - } - if found == nil { - return nil, errors.New("not enough identical responses found") - } - return found, nil -} - func SanitizeLogString(s string) string { tooLongSuffix := "" if len(s) > maxLoggedStringLen { diff --git a/core/capabilities/remote/utils_test.go b/core/capabilities/remote/utils_test.go index 6707e6ffb25..360ef9000ba 100644 --- a/core/capabilities/remote/utils_test.go +++ b/core/capabilities/remote/utils_test.go @@ -10,43 +10,39 @@ import ( ragetypes "github.com/smartcontractkit/libocr/ragep2p/types" - commoncap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" - "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" - "github.com/smartcontractkit/chainlink-common/pkg/values" - "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" ) const ( - capId1 = "cap1" - capId2 = "cap2" - donId1 = uint32(1) + capID1 = "cap1" + capID2 = "cap2" + donID1 = uint32(1) payload1 = "hello world" payload2 = "goodbye world" ) func TestValidateMessage(t *testing.T) { - privKey1, peerId1 := newKeyPair(t) - _, peerId2 := newKeyPair(t) + privKey1, peerID1 := newKeyPair(t) + _, peerID2 := newKeyPair(t) // valid - p2pMsg := encodeAndSign(t, privKey1, peerId1, peerId2, capId1, donId1, []byte(payload1)) - body, err := remote.ValidateMessage(p2pMsg, peerId2) + p2pMsg := encodeAndSign(t, privKey1, peerID1, peerID2, capID1, donID1, []byte(payload1)) + body, err := remote.ValidateMessage(p2pMsg, peerID2) require.NoError(t, err) - require.Equal(t, peerId1[:], body.Sender) + require.Equal(t, peerID1[:], body.Sender) require.Equal(t, payload1, string(body.Payload)) // invalid sender - p2pMsg = encodeAndSign(t, privKey1, peerId1, peerId2, capId1, donId1, []byte(payload1)) - p2pMsg.Sender = peerId2 - _, err = remote.ValidateMessage(p2pMsg, peerId2) + p2pMsg = encodeAndSign(t, privKey1, peerID1, peerID2, capID1, donID1, []byte(payload1)) + p2pMsg.Sender = peerID2 + _, err = remote.ValidateMessage(p2pMsg, peerID2) require.Error(t, err) // invalid receiver - p2pMsg = encodeAndSign(t, privKey1, peerId1, peerId2, capId1, donId1, []byte(payload1)) - _, err = remote.ValidateMessage(p2pMsg, peerId1) + p2pMsg = encodeAndSign(t, privKey1, peerID1, peerID2, capID1, donID1, []byte(payload1)) + _, err = remote.ValidateMessage(p2pMsg, peerID1) require.Error(t, err) } @@ -58,12 +54,12 @@ func newKeyPair(t *testing.T) (ed25519.PrivateKey, ragetypes.PeerID) { return privKey, peerID } -func encodeAndSign(t *testing.T, senderPrivKey ed25519.PrivateKey, senderId p2ptypes.PeerID, receiverId p2ptypes.PeerID, capabilityId string, donId uint32, payload []byte) p2ptypes.Message { +func encodeAndSign(t *testing.T, senderPrivKey ed25519.PrivateKey, senderID p2ptypes.PeerID, receiverID p2ptypes.PeerID, capabilityID string, donID uint32, payload []byte) p2ptypes.Message { body := remotetypes.MessageBody{ - Sender: senderId[:], - Receiver: receiverId[:], - CapabilityId: capabilityId, - CapabilityDonId: donId, + Sender: senderID[:], + Receiver: receiverID[:], + CapabilityId: capabilityID, + CapabilityDonId: donID, Payload: payload, } rawBody, err := proto.Marshal(&body) @@ -78,7 +74,7 @@ func encodeAndSign(t *testing.T, senderPrivKey ed25519.PrivateKey, senderId p2pt require.NoError(t, err) return p2ptypes.Message{ - Sender: senderId, + Sender: senderID, Payload: rawMsg, } } @@ -89,41 +85,6 @@ func TestToPeerID(t *testing.T) { require.Equal(t, "12D3KooWD8QYTQVYjB6oog4Ej8PcPpqTrPRnxLQap8yY8KUQRVvq", id.String()) } -func TestDefaultModeAggregator_Aggregate(t *testing.T) { - val, err := values.NewMap(triggerEvent1) - require.NoError(t, err) - capResponse1 := commoncap.TriggerResponse{ - Event: commoncap.TriggerEvent{ - Outputs: val, - }, - Err: nil, - } - marshaled1, err := pb.MarshalTriggerResponse(capResponse1) - require.NoError(t, err) - - val2, err := values.NewMap(triggerEvent2) - require.NoError(t, err) - capResponse2 := commoncap.TriggerResponse{ - Event: commoncap.TriggerEvent{ - Outputs: val2, - }, - Err: nil, - } - marshaled2, err := pb.MarshalTriggerResponse(capResponse2) - require.NoError(t, err) - - agg := remote.NewDefaultModeAggregator(2) - _, err = agg.Aggregate("", [][]byte{marshaled1}) - require.Error(t, err) - - _, err = agg.Aggregate("", [][]byte{marshaled1, marshaled2}) - require.Error(t, err) - - res, err := agg.Aggregate("", [][]byte{marshaled1, marshaled2, marshaled1}) - require.NoError(t, err) - require.Equal(t, res, capResponse1) -} - func TestSanitizeLogString(t *testing.T) { require.Equal(t, "hello", remote.SanitizeLogString("hello")) require.Equal(t, "[UNPRINTABLE] 0a", remote.SanitizeLogString("\n")) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index fe37eb853a8..972dd4ff4a2 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -33,7 +33,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.20241214155818-b403079b2805 + github.com/smartcontractkit/chainlink-common v0.4.1-0.20241217120918-bbe318cd0760 github.com/smartcontractkit/libocr v0.0.0-20241007185508-adbe57025f12 github.com/spf13/cobra v1.8.1 github.com/spf13/viper v1.19.0 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 7dfd0fe5097..3338519266d 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1150,8 +1150,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-20241218114855-f74219171000 h1:6Zzr/R1j6P7bbvcUlt5WUIbItvrrGdGzIsiAzQezcwo= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000/go.mod h1:ncjd6mPZSRlelEqH/2KeLE1pU3UlqzBSn8RYkEoECzY= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805 h1:Pz8jB/6qe10xT10h2S3LFYJrnebNpG5rJ/w16HZGwPQ= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805/go.mod h1:yti7e1+G9hhkYhj+L5sVUULn9Bn3bBL5/AxaNqdJ5YQ= +github.com/smartcontractkit/chainlink-common v0.4.1-0.20241217120918-bbe318cd0760 h1:lB5A3TP0zOVuu1n0kEm6d8/o/4Knh6HLvsU/GChk+sI= +github.com/smartcontractkit/chainlink-common v0.4.1-0.20241217120918-bbe318cd0760/go.mod h1:yti7e1+G9hhkYhj+L5sVUULn9Bn3bBL5/AxaNqdJ5YQ= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e h1:PRoeby6ZlTuTkv2f+7tVU4+zboTfRzI+beECynF4JQ0= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e/go.mod h1:mUh5/woemsVaHgTorA080hrYmO3syBCmPdnWc/5dOqk= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241216163550-fa030d178ba3 h1:aeiBdBHGY8QNftps+VqrIk6OnfeeOD5z4jrAabW4ZSc= diff --git a/deployment/go.mod b/deployment/go.mod index 0f9e66bbb75..d618c38e838 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -29,7 +29,7 @@ require ( github.com/smartcontractkit/ccip-owner-contracts v0.0.0-salt-fix github.com/smartcontractkit/chain-selectors v1.0.34 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805 + github.com/smartcontractkit/chainlink-common v0.4.1-0.20241217120918-bbe318cd0760 github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.13 github.com/smartcontractkit/libocr v0.0.0-20241007185508-adbe57025f12 diff --git a/deployment/go.sum b/deployment/go.sum index 8e4feda0e82..76546853c38 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1417,8 +1417,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-20241218114855-f74219171000 h1:6Zzr/R1j6P7bbvcUlt5WUIbItvrrGdGzIsiAzQezcwo= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000/go.mod h1:ncjd6mPZSRlelEqH/2KeLE1pU3UlqzBSn8RYkEoECzY= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805 h1:Pz8jB/6qe10xT10h2S3LFYJrnebNpG5rJ/w16HZGwPQ= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805/go.mod h1:yti7e1+G9hhkYhj+L5sVUULn9Bn3bBL5/AxaNqdJ5YQ= +github.com/smartcontractkit/chainlink-common v0.4.1-0.20241217120918-bbe318cd0760 h1:lB5A3TP0zOVuu1n0kEm6d8/o/4Knh6HLvsU/GChk+sI= +github.com/smartcontractkit/chainlink-common v0.4.1-0.20241217120918-bbe318cd0760/go.mod h1:yti7e1+G9hhkYhj+L5sVUULn9Bn3bBL5/AxaNqdJ5YQ= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e h1:PRoeby6ZlTuTkv2f+7tVU4+zboTfRzI+beECynF4JQ0= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e/go.mod h1:mUh5/woemsVaHgTorA080hrYmO3syBCmPdnWc/5dOqk= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241216163550-fa030d178ba3 h1:aeiBdBHGY8QNftps+VqrIk6OnfeeOD5z4jrAabW4ZSc= diff --git a/go.mod b/go.mod index da089c15665..e97f949b065 100644 --- a/go.mod +++ b/go.mod @@ -79,7 +79,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.34 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805 + github.com/smartcontractkit/chainlink-common v0.4.1-0.20241217120918-bbe318cd0760 github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241216163550-fa030d178ba3 github.com/smartcontractkit/chainlink-feeds v0.1.1 diff --git a/go.sum b/go.sum index 28392668c87..5d3b9db6b21 100644 --- a/go.sum +++ b/go.sum @@ -1139,8 +1139,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-20241218114855-f74219171000 h1:6Zzr/R1j6P7bbvcUlt5WUIbItvrrGdGzIsiAzQezcwo= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000/go.mod h1:ncjd6mPZSRlelEqH/2KeLE1pU3UlqzBSn8RYkEoECzY= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805 h1:Pz8jB/6qe10xT10h2S3LFYJrnebNpG5rJ/w16HZGwPQ= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805/go.mod h1:yti7e1+G9hhkYhj+L5sVUULn9Bn3bBL5/AxaNqdJ5YQ= +github.com/smartcontractkit/chainlink-common v0.4.1-0.20241217120918-bbe318cd0760 h1:lB5A3TP0zOVuu1n0kEm6d8/o/4Knh6HLvsU/GChk+sI= +github.com/smartcontractkit/chainlink-common v0.4.1-0.20241217120918-bbe318cd0760/go.mod h1:yti7e1+G9hhkYhj+L5sVUULn9Bn3bBL5/AxaNqdJ5YQ= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e h1:PRoeby6ZlTuTkv2f+7tVU4+zboTfRzI+beECynF4JQ0= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e/go.mod h1:mUh5/woemsVaHgTorA080hrYmO3syBCmPdnWc/5dOqk= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241216163550-fa030d178ba3 h1:aeiBdBHGY8QNftps+VqrIk6OnfeeOD5z4jrAabW4ZSc= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 678598a26c5..1f35241e461 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -47,7 +47,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.34 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000 - github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805 + github.com/smartcontractkit/chainlink-common v0.4.1-0.20241217120918-bbe318cd0760 github.com/smartcontractkit/chainlink-protos/job-distributor v0.6.0 github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.2 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.19 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index d846ff5f136..c7cca9094e0 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1438,8 +1438,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-20241218114855-f74219171000 h1:6Zzr/R1j6P7bbvcUlt5WUIbItvrrGdGzIsiAzQezcwo= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000/go.mod h1:ncjd6mPZSRlelEqH/2KeLE1pU3UlqzBSn8RYkEoECzY= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805 h1:Pz8jB/6qe10xT10h2S3LFYJrnebNpG5rJ/w16HZGwPQ= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805/go.mod h1:yti7e1+G9hhkYhj+L5sVUULn9Bn3bBL5/AxaNqdJ5YQ= +github.com/smartcontractkit/chainlink-common v0.4.1-0.20241217120918-bbe318cd0760 h1:lB5A3TP0zOVuu1n0kEm6d8/o/4Knh6HLvsU/GChk+sI= +github.com/smartcontractkit/chainlink-common v0.4.1-0.20241217120918-bbe318cd0760/go.mod h1:yti7e1+G9hhkYhj+L5sVUULn9Bn3bBL5/AxaNqdJ5YQ= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e h1:PRoeby6ZlTuTkv2f+7tVU4+zboTfRzI+beECynF4JQ0= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e/go.mod h1:mUh5/woemsVaHgTorA080hrYmO3syBCmPdnWc/5dOqk= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241216163550-fa030d178ba3 h1:aeiBdBHGY8QNftps+VqrIk6OnfeeOD5z4jrAabW4ZSc= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index e77f701bf12..3f0cf7e952e 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -27,7 +27,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.20241214155818-b403079b2805 + github.com/smartcontractkit/chainlink-common v0.4.1-0.20241217120918-bbe318cd0760 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.19 github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.9 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 6c2117a6e7c..64591b58222 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1429,8 +1429,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-20241218114855-f74219171000 h1:6Zzr/R1j6P7bbvcUlt5WUIbItvrrGdGzIsiAzQezcwo= github.com/smartcontractkit/chainlink-ccip v0.0.0-20241218114855-f74219171000/go.mod h1:ncjd6mPZSRlelEqH/2KeLE1pU3UlqzBSn8RYkEoECzY= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805 h1:Pz8jB/6qe10xT10h2S3LFYJrnebNpG5rJ/w16HZGwPQ= -github.com/smartcontractkit/chainlink-common v0.3.1-0.20241214155818-b403079b2805/go.mod h1:yti7e1+G9hhkYhj+L5sVUULn9Bn3bBL5/AxaNqdJ5YQ= +github.com/smartcontractkit/chainlink-common v0.4.1-0.20241217120918-bbe318cd0760 h1:lB5A3TP0zOVuu1n0kEm6d8/o/4Knh6HLvsU/GChk+sI= +github.com/smartcontractkit/chainlink-common v0.4.1-0.20241217120918-bbe318cd0760/go.mod h1:yti7e1+G9hhkYhj+L5sVUULn9Bn3bBL5/AxaNqdJ5YQ= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e h1:PRoeby6ZlTuTkv2f+7tVU4+zboTfRzI+beECynF4JQ0= github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241202195413-82468150ac1e/go.mod h1:mUh5/woemsVaHgTorA080hrYmO3syBCmPdnWc/5dOqk= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241216163550-fa030d178ba3 h1:aeiBdBHGY8QNftps+VqrIk6OnfeeOD5z4jrAabW4ZSc= From 2e3a707670dad29d46a91089421f17131bcba3cf Mon Sep 17 00:00:00 2001 From: Rafael Felix Correa Date: Wed, 18 Dec 2024 21:40:54 +0100 Subject: [PATCH 23/27] cribbit.sh removed (#15602) --- core/scripts/keystone/README.md | 2 +- integration-tests/crib/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/scripts/keystone/README.md b/core/scripts/keystone/README.md index 9bf6adfff4e..f08f738cb78 100644 --- a/core/scripts/keystone/README.md +++ b/core/scripts/keystone/README.md @@ -51,7 +51,7 @@ If you want to redeploy all resources, then you'll want to do the following: ```bash # From /crib devspace purge --profile keystone # Remove all k8s resources -./cribbit.sh crib- # Purge currently leaves some hanging resources, make a new namespace +DEVSPACE_NAMESPACE=crib- crib init # Purge currently leaves some hanging resources, make a new namespace devspace deploy --profile keysone --clean # Wipe any keystone related persisted data, like artefacts and caches. ``` diff --git a/integration-tests/crib/README.md b/integration-tests/crib/README.md index c37cbfec9c9..b3ba2c41823 100644 --- a/integration-tests/crib/README.md +++ b/integration-tests/crib/README.md @@ -6,7 +6,7 @@ It runs OCRv1 and reboots the environment confirming integration with environmen Go to the [CRIB](https://github.com/smartcontractkit/crib) repository and spin up a cluster. ```shell -./scripts/cribbit.sh crib-oh-my-crib +DEVSPACE_NAMESPACE=crib-oh-my-crib crib init devspace deploy --debug --profile local-dev-simulated-core-ocr1 ``` From 1adf3490db8b9a7acd70ddf685a1e65ef89adfb1 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Wed, 18 Dec 2024 17:33:52 -0600 Subject: [PATCH 24/27] align .golangci.yml files (#15761) --- .golangci.yml | 4 +- deployment/.golangci.yml | 110 +++++++++++++++++++++++++++++--- integration-tests/.golangci.yml | 107 +++++++++++++++++++++++++++++-- 3 files changed, 206 insertions(+), 15 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index a7928ee97de..63b061c2951 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,5 +1,5 @@ run: - timeout: 15m0s + timeout: 15m allow-parallel-runners: true linters: enable: @@ -97,7 +97,7 @@ linters-settings: - name: waitgroup-by-value - name: unconditional-recursion - name: struct-tag - # - name: string-format + - name: string-format - name: string-of-int - name: range-val-address - name: range-val-in-closure diff --git a/deployment/.golangci.yml b/deployment/.golangci.yml index 4a2e2b4a47c..ff1303e26ce 100644 --- a/deployment/.golangci.yml +++ b/deployment/.golangci.yml @@ -1,18 +1,33 @@ run: timeout: 15m + allow-parallel-runners: true linters: enable: + - containedctx + - depguard + - errname + - errorlint - exhaustive - exportloopref - - revive + - fatcontext + - ginkgolinter + - gocritic - goimports - gosec + - loggercheck + - mirror - misspell - - rowserrcheck - - errorlint - - containedctx - - fatcontext - noctx + - nolintlint + - perfsprint + - prealloc + - revive + - rowserrcheck + - spancheck + - sqlclosecheck + - testifylint + - unconvert + - whitespace linters-settings: exhaustive: default-signifies-exhaustive: true @@ -26,6 +41,28 @@ linters-settings: govet: enable: - shadow + settings: + printf: + # Additionally check chainlink custom loggers + funcs: + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Tracef + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Debugf + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Infof + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Warnf + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Errorf + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Criticalf + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Panicf + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Fatalf + - (github.com/smartcontractkit/chainlink/v2/core/logger.SugaredLogger).AssumptionViolationf + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Debugf + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Infof + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Warnf + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Errorf + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Panicf + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Fatalf + - (github.com/smartcontractkit/chainlink-common/pkg/logger.SugaredLogger).AssumptionViolationf + - (github.com/smartcontractkit/chainlink-common/pkg/logger.SugaredLogger).Tracef + - (github.com/smartcontractkit/chainlink-common/pkg/logger.SugaredLogger).Criticalf revive: confidence: 0.8 rules: @@ -36,9 +73,10 @@ linters-settings: - name: error-return - name: error-strings - name: error-naming + - name: exported - name: if-return - name: increment-decrement - # - name: var-naming // doesn't work with some generated names + - name: var-naming - name: var-declaration - name: package-comments - name: range @@ -49,7 +87,7 @@ linters-settings: - name: errorf - name: empty-block - name: superfluous-else - #- name: unused-parameter + # - name: unused-parameter - name: unreachable-code - name: redefines-builtin-id - name: waitgroup-by-value @@ -64,13 +102,69 @@ linters-settings: - name: identical-branches - name: get-return # - name: flag-parameter // probably one we should work on doing better at in the future - # - name: early-return // probably one we should work on doing better at in the future + - name: early-return - name: defer - name: constant-logical-expr - name: confusing-naming - name: confusing-results - name: bool-literal-in-expr - name: atomic + depguard: + rules: + main: + list-mode: lax + deny: + - pkg: cosmossdk.io/errors + desc: Use the standard library instead + - pkg: github.com/gofrs/uuid + desc: Use github.com/google/uuid instead + - pkg: github.com/jackc/pgx3 + desc: Use github.com/jackc/pgx4 instead + - pkg: github.com/jackc/pgx5 + desc: Use github.com/jackc/pgx4 instead + - pkg: github.com/satori/go.uuid + desc: Use github.com/google/uuid instead + - pkg: github.com/test-go/testify/assert + desc: Use github.com/stretchr/testify/assert instead + - pkg: github.com/test-go/testify/mock + desc: Use github.com/stretchr/testify/mock instead + - pkg: github.com/test-go/testify/require + desc: Use github.com/stretchr/testify/require instead + - pkg: go.uber.org/multierr + desc: Use the standard library instead, for example https://pkg.go.dev/errors#Join + - pkg: gopkg.in/guregu/null.v1 + desc: Use gopkg.in/guregu/null.v4 instead + - pkg: gopkg.in/guregu/null.v2 + desc: Use gopkg.in/guregu/null.v4 instead + - pkg: gopkg.in/guregu/null.v3 + desc: Use gopkg.in/guregu/null.v4 instead + - pkg: github.com/go-gorm/gorm + desc: Use github.com/jmoiron/sqlx directly instead + loggercheck: + # Check that *w logging functions have even number of args (i.e., well formed key-value pairs). + rules: + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Tracew + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Debugw + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Infow + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Warnw + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Errorw + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Criticalw + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Panicw + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Fatalw + - (github.com/smartcontractkit/chainlink/v2/core/logger.SugaredLogger).AssumptionViolationw + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Debugw + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Infow + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Warnw + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Errorw + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Panicw + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Fatalw + - (github.com/smartcontractkit/chainlink-common/pkg/logger.SugaredLogger).AssumptionViolationw + - (github.com/smartcontractkit/chainlink-common/pkg/logger.SugaredLogger).Tracew + - (github.com/smartcontractkit/chainlink-common/pkg/logger.SugaredLogger).Criticalw + - (github.com/smartcontractkit/chainlink-common/pkg/logger.SugaredLogger).With + nolintlint: + require-specific: true + require-explanation: true issues: exclude-rules: - path: memory/(.+)\.go diff --git a/integration-tests/.golangci.yml b/integration-tests/.golangci.yml index 8969110d988..337555e17cb 100644 --- a/integration-tests/.golangci.yml +++ b/integration-tests/.golangci.yml @@ -1,15 +1,33 @@ run: timeout: 15m + allow-parallel-runners: true linters: enable: + - containedctx + - depguard + - errname + - errorlint - exhaustive - exportloopref - - revive + - fatcontext + - ginkgolinter + - gocritic - goimports - gosec + - loggercheck + - mirror - misspell + - noctx + - nolintlint + - perfsprint + - prealloc + - revive - rowserrcheck - - errorlint + - spancheck + - sqlclosecheck + - testifylint + - unconvert + - whitespace linters-settings: exhaustive: default-signifies-exhaustive: true @@ -23,6 +41,28 @@ linters-settings: govet: enable: - shadow + settings: + printf: + # Additionally check chainlink custom loggers + funcs: + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Tracef + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Debugf + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Infof + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Warnf + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Errorf + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Criticalf + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Panicf + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Fatalf + - (github.com/smartcontractkit/chainlink/v2/core/logger.SugaredLogger).AssumptionViolationf + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Debugf + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Infof + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Warnf + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Errorf + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Panicf + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Fatalf + - (github.com/smartcontractkit/chainlink-common/pkg/logger.SugaredLogger).AssumptionViolationf + - (github.com/smartcontractkit/chainlink-common/pkg/logger.SugaredLogger).Tracef + - (github.com/smartcontractkit/chainlink-common/pkg/logger.SugaredLogger).Criticalf revive: confidence: 0.8 rules: @@ -33,9 +73,10 @@ linters-settings: - name: error-return - name: error-strings - name: error-naming + - name: exported - name: if-return - name: increment-decrement - # - name: var-naming // doesn't work with some generated names + - name: var-naming - name: var-declaration - name: package-comments - name: range @@ -46,7 +87,7 @@ linters-settings: - name: errorf - name: empty-block - name: superfluous-else - #- name: unused-parameter + # - name: unused-parameter - name: unreachable-code - name: redefines-builtin-id - name: waitgroup-by-value @@ -61,13 +102,69 @@ linters-settings: - name: identical-branches - name: get-return # - name: flag-parameter // probably one we should work on doing better at in the future - # - name: early-return // probably one we should work on doing better at in the future + - name: early-return - name: defer - name: constant-logical-expr - name: confusing-naming - name: confusing-results - name: bool-literal-in-expr - name: atomic + depguard: + rules: + main: + list-mode: lax + deny: + - pkg: cosmossdk.io/errors + desc: Use the standard library instead + - pkg: github.com/gofrs/uuid + desc: Use github.com/google/uuid instead + - pkg: github.com/jackc/pgx3 + desc: Use github.com/jackc/pgx4 instead + - pkg: github.com/jackc/pgx5 + desc: Use github.com/jackc/pgx4 instead + - pkg: github.com/satori/go.uuid + desc: Use github.com/google/uuid instead + - pkg: github.com/test-go/testify/assert + desc: Use github.com/stretchr/testify/assert instead + - pkg: github.com/test-go/testify/mock + desc: Use github.com/stretchr/testify/mock instead + - pkg: github.com/test-go/testify/require + desc: Use github.com/stretchr/testify/require instead + - pkg: go.uber.org/multierr + desc: Use the standard library instead, for example https://pkg.go.dev/errors#Join + - pkg: gopkg.in/guregu/null.v1 + desc: Use gopkg.in/guregu/null.v4 instead + - pkg: gopkg.in/guregu/null.v2 + desc: Use gopkg.in/guregu/null.v4 instead + - pkg: gopkg.in/guregu/null.v3 + desc: Use gopkg.in/guregu/null.v4 instead + - pkg: github.com/go-gorm/gorm + desc: Use github.com/jmoiron/sqlx directly instead + loggercheck: + # Check that *w logging functions have even number of args (i.e., well formed key-value pairs). + rules: + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Tracew + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Debugw + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Infow + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Warnw + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Errorw + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Criticalw + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Panicw + - (github.com/smartcontractkit/chainlink/v2/core/logger.Logger).Fatalw + - (github.com/smartcontractkit/chainlink/v2/core/logger.SugaredLogger).AssumptionViolationw + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Debugw + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Infow + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Warnw + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Errorw + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Panicw + - (github.com/smartcontractkit/chainlink-common/pkg/logger.Logger).Fatalw + - (github.com/smartcontractkit/chainlink-common/pkg/logger.SugaredLogger).AssumptionViolationw + - (github.com/smartcontractkit/chainlink-common/pkg/logger.SugaredLogger).Tracew + - (github.com/smartcontractkit/chainlink-common/pkg/logger.SugaredLogger).Criticalw + - (github.com/smartcontractkit/chainlink-common/pkg/logger.SugaredLogger).With + nolintlint: + require-specific: true + require-explanation: true issues: exclude-rules: - text: "^G404: Use of weak random number generator" From 7f28ce042f6d0272e602a5c9eb4b0d48fae5a821 Mon Sep 17 00:00:00 2001 From: Dmytro Haidashenko <34754799+dhaidashenko@users.noreply.github.com> Date: Thu, 19 Dec 2024 07:33:14 +0100 Subject: [PATCH 25/27] NONEVM-745 solana schema (#15171) * Add Solana db schema * solana db schema * add missing index on solana filters * ensure subkey naming is consistent * remove redundant constraint * added is_deleted column to solana.log_poller_filters * fix solana logpoller filter name constraint * bump migration number --------- Co-authored-by: Domino Valdano <2644901+reductionista@users.noreply.github.com> --- .../migrations/0262_add_solana_schema.sql | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 core/store/migrate/migrations/0262_add_solana_schema.sql diff --git a/core/store/migrate/migrations/0262_add_solana_schema.sql b/core/store/migrate/migrations/0262_add_solana_schema.sql new file mode 100644 index 00000000000..035d3ff3d61 --- /dev/null +++ b/core/store/migrate/migrations/0262_add_solana_schema.sql @@ -0,0 +1,72 @@ +-- +goose Up +-- +goose StatementBegin +-- This removes evm from the search path, to avoid risk of an unqualified query intended to act on a Solana table accidentally +-- acting on the corresponding evm table. This makes schema qualification mandatory for all chain-specific queries. +SET search_path TO public; +CREATE SCHEMA solana; + +CREATE TABLE solana.log_poller_filters ( + id BIGSERIAL PRIMARY KEY, + chain_id TEXT NOT NULL, -- use human-readable name instead of genesis block hash to reduce index size by 50% + name TEXT NOT NULL, + address BYTEA NOT NULL, + event_name TEXT NOT NULL, + event_sig BYTEA NOT NULL, + starting_block BIGINT NOT NULL, + event_idl TEXT, + subkey_paths json, -- A list of subkeys to be indexed, represented by their json paths in the event struct. Forced to use json's 2d array as text[][] requires all paths to have equal length. + retention BIGINT NOT NULL DEFAULT 0, -- we don’t have to implement this initially, but good to include it in the schema + max_logs_kept BIGINT NOT NULL DEFAULT 0, -- same as retention, no need to implement yet + is_deleted BOOLEAN NOT NULL DEFAULT FALSE +); + +CREATE UNIQUE INDEX IF NOT EXISTS solana_log_poller_filter_name ON solana.log_poller_filters (chain_id, name) WHERE NOT is_deleted; + +CREATE TABLE solana.logs ( + id BIGSERIAL PRIMARY KEY, + filter_id BIGINT NOT NULL REFERENCES solana.log_poller_filters (id) ON DELETE CASCADE, + chain_id TEXT not null, -- use human-readable name instead of genesis block hash to reduce index size by 50% + log_index bigint not null, + block_hash bytea not null, + block_number bigint not null CHECK (block_number > 0), + block_timestamp timestamp with time zone not null, + address bytea not null, + event_sig bytea not null, + subkey_values bytea[] not null, + tx_hash bytea not null, + data bytea not null, + created_at timestamp with time zone not null, + expires_at timestamp with time zone null, -- null to indicate no timebase expiry + sequence_num bigint not null +); + +CREATE INDEX IF NOT EXISTS solana_logs_idx_by_timestamp ON solana.logs (chain_id, address, event_sig, block_timestamp, block_number); + +CREATE INDEX IF NOT EXISTS solana_logs_idx ON solana.logs (chain_id, block_number, address, event_sig); + +CREATE INDEX IF NOT EXISTS solana_logs_idx_subkey_one ON solana.logs ((subkey_values[1])); +CREATE INDEX IF NOT EXISTS solana_logs_idx_subkey_two ON solana.logs ((subkey_values[2])); +CREATE INDEX IF NOT EXISTS solana_logs_idx_subkey_three ON solana.logs ((subkey_values[3])); +CREATE INDEX IF NOT EXISTS solana_logs_idx_subkey_four ON solana.logs ((subkey_values[4])); + +CREATE INDEX IF NOT EXISTS solana_logs_idx_tx_hash ON solana.logs (tx_hash); + +-- Useful for the current form of those queries: WHERE chain_id = $1 AND address = $2 AND event_sig = $3 ... ORDER BY block_number, log_index +-- log_index is not included in this index because it increases the index size by ~ 10% for a likely negligible performance benefit +CREATE INDEX IF NOT EXISTS solana_logs_idx_chain_address_event_block ON solana.logs (chain_id, address, event_sig, block_number); + +CREATE UNIQUE INDEX IF NOT EXISTS solana_logs_idx_chain_filter_block_logindex ON solana.logs USING btree (chain_id, filter_id, block_number, log_index); + +-- +goose StatementEnd + + +-- +goose Down +-- +goose StatementBegin + +DROP TABLE IF EXISTS solana.logs; +DROP TABLE IF EXISTS solana.log_poller_filters; + +DROP SCHEMA solana; + +SET search_path TO public,evm; +-- +goose StatementEnd From 37d30814fda19dfc61f7952a691b96036df2ed36 Mon Sep 17 00:00:00 2001 From: pavel-raykov <165708424+pavel-raykov@users.noreply.github.com> Date: Thu, 19 Dec 2024 07:54:08 +0100 Subject: [PATCH 26/27] Gracefully fail if CL_DATABASE_URL is not set. (#15741) --- .changeset/beige-geckos-explode.md | 5 +++++ core/services/chainlink/config_database.go | 3 +++ 2 files changed, 8 insertions(+) create mode 100644 .changeset/beige-geckos-explode.md diff --git a/.changeset/beige-geckos-explode.md b/.changeset/beige-geckos-explode.md new file mode 100644 index 00000000000..9f06a9c989b --- /dev/null +++ b/.changeset/beige-geckos-explode.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +#updated Gracefully fail if CL_DATABASE_URL is not set. diff --git a/core/services/chainlink/config_database.go b/core/services/chainlink/config_database.go index fd8aa96419d..27e61479146 100644 --- a/core/services/chainlink/config_database.go +++ b/core/services/chainlink/config_database.go @@ -107,6 +107,9 @@ func (d *databaseConfig) DefaultQueryTimeout() time.Duration { } func (d *databaseConfig) URL() url.URL { + if d.s.URL == nil { + return url.URL{} + } return *d.s.URL.URL() } From d5e21848701742640d5d9e6c0acfe17f23d64a51 Mon Sep 17 00:00:00 2001 From: Gabriel Paradiso Date: Thu, 19 Dec 2024 10:24:09 +0100 Subject: [PATCH 27/27] fix: correctly propagate errors whenever the fetcher fails to download the artifacts (#15758) --- core/services/workflows/syncer/fetcher.go | 4 +++ .../services/workflows/syncer/fetcher_test.go | 34 +++++++++++++++++++ core/services/workflows/syncer/handler.go | 6 ++-- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/core/services/workflows/syncer/fetcher.go b/core/services/workflows/syncer/fetcher.go index 6a80739bbfe..5c8856d58c1 100644 --- a/core/services/workflows/syncer/fetcher.go +++ b/core/services/workflows/syncer/fetcher.go @@ -100,5 +100,9 @@ func (s *FetcherService) Fetch(ctx context.Context, url string) ([]byte, error) return nil, err } + if payload.ExecutionError { + return nil, fmt.Errorf("execution error from gateway: %s", payload.ErrorMessage) + } + return payload.Body, nil } diff --git a/core/services/workflows/syncer/fetcher_test.go b/core/services/workflows/syncer/fetcher_test.go index ee59d22608a..017b052f8ab 100644 --- a/core/services/workflows/syncer/fetcher_test.go +++ b/core/services/workflows/syncer/fetcher_test.go @@ -58,6 +58,40 @@ func TestNewFetcherService(t *testing.T) { expectedPayload := []byte("response body") require.Equal(t, expectedPayload, payload) }) + + t.Run("NOK-response_payload_too_large", func(t *testing.T) { + headers := map[string]string{"Content-Type": "application/json"} + responsePayload, err := json.Marshal(ghcapabilities.Response{ + StatusCode: 400, + Headers: headers, + ErrorMessage: "http: request body too large", + ExecutionError: true, + }) + require.NoError(t, err) + gatewayResponse := &api.Message{ + Body: api.MessageBody{ + MessageId: msgID, + Method: ghcapabilities.MethodWebAPITarget, + Payload: responsePayload, + }, + } + + connector.EXPECT().AddHandler([]string{capabilities.MethodWorkflowSyncer}, mock.Anything).Return(nil) + + fetcher := NewFetcherService(lggr, wrapper) + require.NoError(t, fetcher.Start(ctx)) + defer fetcher.Close() + + connector.EXPECT().SignAndSendToGateway(mock.Anything, "gateway1", mock.Anything).Run(func(ctx context.Context, gatewayID string, msg *api.MessageBody) { + fetcher.och.HandleGatewayMessage(ctx, "gateway1", gatewayResponse) + }).Return(nil).Times(1) + connector.EXPECT().DonID().Return("don-id") + connector.EXPECT().AwaitConnection(matches.AnyContext, "gateway1").Return(nil) + connector.EXPECT().GatewayIDs().Return([]string{"gateway1", "gateway2"}) + + _, err = fetcher.Fetch(ctx, url) + require.Error(t, err, "execution error from gateway: http: request body too large") + }) } func gatewayResponse(t *testing.T, msgID string) *api.Message { diff --git a/core/services/workflows/syncer/handler.go b/core/services/workflows/syncer/handler.go index 534dfd57e7b..ef5455bfbc8 100644 --- a/core/services/workflows/syncer/handler.go +++ b/core/services/workflows/syncer/handler.go @@ -497,19 +497,19 @@ func (h *eventHandler) getWorkflowArtifacts( if err != nil { binary, err2 := h.fetcher(ctx, payload.BinaryURL) if err2 != nil { - return nil, nil, fmt.Errorf("failed to fetch binary from %s : %w", payload.BinaryURL, err) + return nil, nil, fmt.Errorf("failed to fetch binary from %s : %w", payload.BinaryURL, err2) } decodedBinary, err2 := base64.StdEncoding.DecodeString(string(binary)) if err2 != nil { - return nil, nil, fmt.Errorf("failed to decode binary: %w", err) + return nil, nil, fmt.Errorf("failed to decode binary: %w", err2) } var config []byte if payload.ConfigURL != "" { config, err2 = h.fetcher(ctx, payload.ConfigURL) if err2 != nil { - return nil, nil, fmt.Errorf("failed to fetch config from %s : %w", payload.ConfigURL, err) + return nil, nil, fmt.Errorf("failed to fetch config from %s : %w", payload.ConfigURL, err2) } } return decodedBinary, config, nil