From c2a1b26ed24f50a30cac95bd25a8f517f3367c8c Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 9 Nov 2023 11:42:44 -0500 Subject: [PATCH 1/7] Actually serialize the LatestBlocks part of the observation (#11237) * Actually serialize the LatestBlocks part of the observation * Fix tests * Regenerate mocks --- .gitignore | 6 +- common/headtracker/head_tracker.go | 3 + common/headtracker/types/mocks/head.go | 20 +++- common/types/head.go | 9 +- common/types/mocks/head.go | 20 +++- .../evm/client/simulated_backend_client.go | 2 +- core/chains/evm/types/models.go | 4 + core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- .../relay/evm/mercury/v1/data_source.go | 3 +- go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- tools/flakeytests/coverage.txt | 93 ------------------- 15 files changed, 68 insertions(+), 110 deletions(-) delete mode 100644 tools/flakeytests/coverage.txt diff --git a/.gitignore b/.gitignore index 61ebfab0e9b..48e228eb836 100644 --- a/.gitignore +++ b/.gitignore @@ -79,7 +79,9 @@ MacOSX* contracts/yarn.lock - # Ignore DevSpace cache and log folder .devspace/ -go.work* \ No newline at end of file +go.work* + +# This sometimes shows up for some reason +tools/flakeytests/coverage.txt diff --git a/common/headtracker/head_tracker.go b/common/headtracker/head_tracker.go index c24dde595cf..54262dd93f7 100644 --- a/common/headtracker/head_tracker.go +++ b/common/headtracker/head_tracker.go @@ -197,6 +197,9 @@ func (ht *HeadTracker[HTH, S, ID, BLOCK_HASH]) handleNewHead(ctx context.Context "blockHeight", head.BlockNumber(), "blockHash", head.BlockHash(), "parentHeadHash", head.GetParentHash(), + "blockTs", head.GetTimestamp(), + "blockTsUnix", head.GetTimestamp().Unix(), + "blockDifficulty", head.BlockDifficulty(), ) err := ht.headSaver.Save(ctx, head) diff --git a/common/headtracker/types/mocks/head.go b/common/headtracker/types/mocks/head.go index a56590b6ef3..1de1f78de8c 100644 --- a/common/headtracker/types/mocks/head.go +++ b/common/headtracker/types/mocks/head.go @@ -3,9 +3,13 @@ package mocks import ( + time "time" + + mock "github.com/stretchr/testify/mock" + types "github.com/smartcontractkit/chainlink/v2/common/types" + utils "github.com/smartcontractkit/chainlink/v2/core/utils" - mock "github.com/stretchr/testify/mock" ) // Head is an autogenerated mock type for the Head type @@ -131,6 +135,20 @@ func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetParentHash() BLOCK_HASH { return r0 } +// GetTimestamp provides a mock function with given fields: +func (_m *Head[BLOCK_HASH, CHAIN_ID]) GetTimestamp() time.Time { + ret := _m.Called() + + var r0 time.Time + if rf, ok := ret.Get(0).(func() time.Time); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(time.Time) + } + + return r0 +} + // HasChainID provides a mock function with given fields: func (_m *Head[BLOCK_HASH, CHAIN_ID]) HasChainID() bool { ret := _m.Called() diff --git a/common/types/head.go b/common/types/head.go index bef9c30d9e9..000bad2390e 100644 --- a/common/types/head.go +++ b/common/types/head.go @@ -1,6 +1,10 @@ package types -import "github.com/smartcontractkit/chainlink/v2/core/utils" +import ( + "time" + + "github.com/smartcontractkit/chainlink/v2/core/utils" +) // Head provides access to a chain's head, as needed by the TxManager. // This is a generic interface which ALL chains will implement. @@ -10,6 +14,9 @@ type Head[BLOCK_HASH Hashable] interface { // BlockNumber is the head's block number BlockNumber() int64 + // Timestamp the time of mining of the block + GetTimestamp() time.Time + // ChainLength returns the length of the chain followed by recursively looking up parents ChainLength() uint32 diff --git a/common/types/mocks/head.go b/common/types/mocks/head.go index 816a9234a3c..82fd910a08b 100644 --- a/common/types/mocks/head.go +++ b/common/types/mocks/head.go @@ -3,9 +3,13 @@ package mocks import ( + time "time" + + mock "github.com/stretchr/testify/mock" + types "github.com/smartcontractkit/chainlink/v2/common/types" + utils "github.com/smartcontractkit/chainlink/v2/core/utils" - mock "github.com/stretchr/testify/mock" ) // Head is an autogenerated mock type for the Head type @@ -117,6 +121,20 @@ func (_m *Head[BLOCK_HASH]) GetParentHash() BLOCK_HASH { return r0 } +// GetTimestamp provides a mock function with given fields: +func (_m *Head[BLOCK_HASH]) GetTimestamp() time.Time { + ret := _m.Called() + + var r0 time.Time + if rf, ok := ret.Get(0).(func() time.Time); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(time.Time) + } + + return r0 +} + // HashAtHeight provides a mock function with given fields: blockNum func (_m *Head[BLOCK_HASH]) HashAtHeight(blockNum int64) BLOCK_HASH { ret := _m.Called(blockNum) diff --git a/core/chains/evm/client/simulated_backend_client.go b/core/chains/evm/client/simulated_backend_client.go index d542e98e6eb..f4ad6a65a1a 100644 --- a/core/chains/evm/client/simulated_backend_client.go +++ b/core/chains/evm/client/simulated_backend_client.go @@ -301,7 +301,7 @@ func (c *SimulatedBackendClient) SubscribeNewHead( case h := <-ch: var head *evmtypes.Head if h != nil { - head = &evmtypes.Head{Number: h.Number.Int64(), Hash: h.Hash(), ParentHash: h.ParentHash, Parent: lastHead, EVMChainID: utils.NewBig(c.chainId)} + head = &evmtypes.Head{Difficulty: (*utils.Big)(h.Difficulty), Timestamp: time.Unix(int64(h.Time), 0), Number: h.Number.Int64(), Hash: h.Hash(), ParentHash: h.ParentHash, Parent: lastHead, EVMChainID: utils.NewBig(c.chainId)} lastHead = head } select { diff --git a/core/chains/evm/types/models.go b/core/chains/evm/types/models.go index 6db5d49575c..c2d61e00703 100644 --- a/core/chains/evm/types/models.go +++ b/core/chains/evm/types/models.go @@ -76,6 +76,10 @@ func (h *Head) GetParent() commontypes.Head[common.Hash] { return h.Parent } +func (h *Head) GetTimestamp() time.Time { + return h.Timestamp +} + func (h *Head) BlockDifficulty() *utils.Big { return h.Difficulty } diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 3adcc130bc0..5f881f354e6 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -304,7 +304,7 @@ require ( github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231109141932-cb1ea9020255 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231107132621-6de9cc4fb264 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108205920-694ce17a4a78 // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 7f5d0e227d6..1d455305a94 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1464,8 +1464,8 @@ github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumv github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231109141932-cb1ea9020255 h1:Pt6c7bJU9wIN6PQQnmN8UmYYH6lpfiQ6U/B8yEC2s5s= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231109141932-cb1ea9020255/go.mod h1:EHppaccd/LTlTMI2o4dmBHe4BknEgEFFDjDGMNuGb3k= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231107132621-6de9cc4fb264 h1:64bH7MmWzcy5tB16x40266DzgKr2iIVcDPjOro6Q3Us= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231107132621-6de9cc4fb264/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108205920-694ce17a4a78 h1:ZBsxdB/5iIpl/tWhXe/RHrOwBG7pbKOMeppy5Zt2BVc= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108205920-694ce17a4a78/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 h1:DaPSVnxe7oz1QJ+AVIhQWs1W3ubQvwvGo9NbHpMs1OQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05/go.mod h1:o0Pn1pbaUluboaK6/yhf8xf7TiFCkyFl6WUOdwqamuU= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb h1:HiluOfEVGOQTM6BTDImOqYdMZZ7qq7fkZ3TJdmItNr8= diff --git a/core/services/relay/evm/mercury/v1/data_source.go b/core/services/relay/evm/mercury/v1/data_source.go index 1b16dc76f98..0f8f56f46e4 100644 --- a/core/services/relay/evm/mercury/v1/data_source.go +++ b/core/services/relay/evm/mercury/v1/data_source.go @@ -42,8 +42,7 @@ var ( ) ) -// nBlocksObservation controls how many blocks are included in the LatestBlocks observation -const nBlocksObservation int = 5 +const nBlocksObservation int = relaymercuryv1.MaxAllowedBlocks type Runner interface { ExecuteRun(ctx context.Context, spec pipeline.Spec, vars pipeline.Vars, l logger.Logger) (run *pipeline.Run, trrs pipeline.TaskRunResults, err error) diff --git a/go.mod b/go.mod index 67896860e09..f35077e9234 100644 --- a/go.mod +++ b/go.mod @@ -66,7 +66,7 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231109141932-cb1ea9020255 - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231107132621-6de9cc4fb264 + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108205920-694ce17a4a78 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb github.com/smartcontractkit/libocr v0.0.0-20231107151413-13e0202ae8d7 diff --git a/go.sum b/go.sum index 89e9aee85fa..2c9d9e53715 100644 --- a/go.sum +++ b/go.sum @@ -1465,8 +1465,8 @@ github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumv github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231109141932-cb1ea9020255 h1:Pt6c7bJU9wIN6PQQnmN8UmYYH6lpfiQ6U/B8yEC2s5s= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231109141932-cb1ea9020255/go.mod h1:EHppaccd/LTlTMI2o4dmBHe4BknEgEFFDjDGMNuGb3k= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231107132621-6de9cc4fb264 h1:64bH7MmWzcy5tB16x40266DzgKr2iIVcDPjOro6Q3Us= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231107132621-6de9cc4fb264/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108205920-694ce17a4a78 h1:ZBsxdB/5iIpl/tWhXe/RHrOwBG7pbKOMeppy5Zt2BVc= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108205920-694ce17a4a78/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 h1:DaPSVnxe7oz1QJ+AVIhQWs1W3ubQvwvGo9NbHpMs1OQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05/go.mod h1:o0Pn1pbaUluboaK6/yhf8xf7TiFCkyFl6WUOdwqamuU= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb h1:HiluOfEVGOQTM6BTDImOqYdMZZ7qq7fkZ3TJdmItNr8= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index c51bd3c4f6e..83657baa011 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -387,7 +387,7 @@ require ( github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231109141932-cb1ea9020255 // indirect - github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231107132621-6de9cc4fb264 // indirect + github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108205920-694ce17a4a78 // indirect github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 // indirect github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 4afa0de1d38..a873f9b7c16 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2369,8 +2369,8 @@ github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumv github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231109141932-cb1ea9020255 h1:Pt6c7bJU9wIN6PQQnmN8UmYYH6lpfiQ6U/B8yEC2s5s= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231109141932-cb1ea9020255/go.mod h1:EHppaccd/LTlTMI2o4dmBHe4BknEgEFFDjDGMNuGb3k= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231107132621-6de9cc4fb264 h1:64bH7MmWzcy5tB16x40266DzgKr2iIVcDPjOro6Q3Us= -github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231107132621-6de9cc4fb264/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108205920-694ce17a4a78 h1:ZBsxdB/5iIpl/tWhXe/RHrOwBG7pbKOMeppy5Zt2BVc= +github.com/smartcontractkit/chainlink-relay v0.1.7-0.20231108205920-694ce17a4a78/go.mod h1:M9U1JV7IQi8Sfj4JR1qSi1tIh6omgW78W/8SHN/8BUQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05 h1:DaPSVnxe7oz1QJ+AVIhQWs1W3ubQvwvGo9NbHpMs1OQ= github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231023133638-72f4e799ab05/go.mod h1:o0Pn1pbaUluboaK6/yhf8xf7TiFCkyFl6WUOdwqamuU= github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231024133459-1ef3a11319eb h1:HiluOfEVGOQTM6BTDImOqYdMZZ7qq7fkZ3TJdmItNr8= diff --git a/tools/flakeytests/coverage.txt b/tools/flakeytests/coverage.txt deleted file mode 100644 index 91640016fe2..00000000000 --- a/tools/flakeytests/coverage.txt +++ /dev/null @@ -1,93 +0,0 @@ -mode: atomic -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:50.103,54.38 4 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:54.38,55.24 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:55.24,62.18 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:62.18,64.5 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:65.4,65.46 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:72.2,73.16 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:73.16,75.3 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:77.2,90.16 3 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:93.63,95.16 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:95.16,97.3 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:99.2,101.16 3 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:101.16,103.3 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:104.2,110.16 4 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:110.16,112.3 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:112.8,112.52 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:112.52,114.18 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:114.18,116.4 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:117.3,117.83 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:119.2,119.12 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:122.81,124.16 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:124.16,126.3 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:128.2,128.31 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/reporter.go:131.77,133.2 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:40.79,44.30 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:44.31,44.32 0 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:46.2,52.3 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:61.75,70.2 8 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:81.45,85.2 3 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:87.75,89.28 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:89.28,91.16 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:91.16,93.19 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:93.19,94.13 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:99.4,99.42 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:99.42,100.13 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:103.4,104.18 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:104.18,106.5 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:110.4,110.39 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:110.39,111.13 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:114.4,114.20 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:115.16,116.32 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:116.32,118.6 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:119.5,119.31 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:120.18,121.38 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:121.38,122.33 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:122.33,124.7 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:125.6,125.32 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:130.3,130.33 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:130.33,132.4 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:134.2,134.19 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:141.106,144.38 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:144.38,146.27 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:146.27,148.4 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:150.3,151.36 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:151.36,155.18 3 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:155.18,161.55 3 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:161.55,162.14 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:164.5,164.32 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:167.4,168.18 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:168.18,170.5 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:172.4,172.25 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:172.25,174.22 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:174.22,175.37 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:175.37,177.7 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:178.6,178.42 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:184.2,184.29 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:187.30,189.16 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:189.16,191.3 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:193.2,194.16 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:194.16,196.3 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:198.2,198.30 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:198.30,200.3 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:200.8,202.3 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/runner.go:204.2,204.43 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:12.74,15.25 3 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:15.25,17.10 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:17.10,19.4 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:21.3,21.10 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:24.2,25.9 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:25.9,27.3 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:29.2,29.16 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:32.88,34.16 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:34.16,36.17 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:36.17,38.4 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:40.3,41.17 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:41.17,43.4 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:45.3,46.17 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:46.17,48.4 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:51.2,52.19 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:53.22,56.17 3 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:56.17,58.4 1 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:60.3,61.19 2 0 -github.com/smartcontractkit/chainlink/v2/tools/flakeytests/utils.go:62.10,63.19 1 0 From 012865049d9a88057e25f2b928315ed12897a8b2 Mon Sep 17 00:00:00 2001 From: Andrei Smirnov Date: Thu, 9 Nov 2023 20:23:30 +0300 Subject: [PATCH 2/7] Functions: ARB+OP cost estimation tweaks (#11102) * Functions: ARB+OP gas tweaks * make wrappers-all * Updated gas snapshot * Single line comments * (refactor): rework ChainSpecificUtil usage to be an additional flat fee, rather than gas price * (test): Add ChainSpecificUtil foundry tests * Regenerate geth wrappers * Regenerate gas snapshot * Amend L1Fee as gas units, not in wei * Prettier * Revert "Amend L1Fee as gas units, not in wei" This reverts commit 75e47cadbe4a7a58fc731bc57b9dfaa7eb8a7898. * Denote that _getCurrentTxL1GasFees's return is in Wei * (refactor) rework FunctionsBilling unit conversion helper to be juels from wei * Changes from review * Regenerate gas snapshot --------- Co-authored-by: Justin Kaseman --- .../gas-snapshots/functions.gas-snapshot | 73 +++--- .../functions/dev/v1_X/ChainSpecificUtil.sol | 78 +++++++ .../functions/dev/v1_X/FunctionsBilling.sol | 34 +-- .../dev/v1_X/FunctionsCoordinator.sol | 9 +- .../tests/v1_X/ChainSpecificUtil.t.sol | 217 ++++++++++++++++++ .../tests/v1_X/FunctionsCoordinator.t.sol | 1 - .../src/v0.8/functions/tests/v1_X/Gas.t.sol | 8 - .../src/v0.8/functions/tests/v1_X/Setup.t.sol | 87 +++++-- .../FunctionsCoordinatorHarness.sol | 5 +- .../functions_coordinator.go | 2 +- ...rapper-dependency-versions-do-not-edit.txt | 2 +- 11 files changed, 434 insertions(+), 82 deletions(-) create mode 100644 contracts/src/v0.8/functions/dev/v1_X/ChainSpecificUtil.sol create mode 100644 contracts/src/v0.8/functions/tests/v1_X/ChainSpecificUtil.t.sol diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index e742be27549..4e891535b77 100644 --- a/contracts/gas-snapshots/functions.gas-snapshot +++ b/contracts/gas-snapshots/functions.gas-snapshot @@ -1,9 +1,18 @@ +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 14497117) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14497095) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14497111) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14508531) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14508508) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14508480) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14508431) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14508420) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14508464) FunctionsBilling_Constructor:test_Constructor_Success() (gas: 14812) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_RevertIfNotRouter() (gas: 13282) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_Success() (gas: 15897) FunctionsBilling_EstimateCost:test_EstimateCost_RevertsIfGasPriceAboveCeiling() (gas: 32458) -FunctionsBilling_EstimateCost:test_EstimateCost_Success() (gas: 53227) -FunctionsBilling_EstimateCost:test_EstimateCost_SuccessLowGasPrice() (gas: 53330) +FunctionsBilling_EstimateCost:test_EstimateCost_Success() (gas: 53807) +FunctionsBilling_EstimateCost:test_EstimateCost_SuccessLowGasPrice() (gas: 53910) FunctionsBilling_GetAdminFee:test_GetAdminFee_Success() (gas: 18226) FunctionsBilling_GetConfig:test_GetConfig_Success() (gas: 23671) FunctionsBilling_GetDONFee:test_GetDONFee_Success() (gas: 15792) @@ -18,39 +27,39 @@ FunctionsBilling_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 18974) FunctionsBilling_UpdateConfig:test_UpdateConfig_Success() (gas: 38251) FunctionsBilling__DisperseFeePool:test__DisperseFeePool_RevertIfNotSet() (gas: 8801) FunctionsClient_Constructor:test_Constructor_Success() (gas: 7573) -FunctionsClient_FulfillRequest:test_FulfillRequest_MaximumGas() (gas: 498114) -FunctionsClient_FulfillRequest:test_FulfillRequest_MinimumGas() (gas: 199285) +FunctionsClient_FulfillRequest:test_FulfillRequest_MaximumGas() (gas: 501740) +FunctionsClient_FulfillRequest:test_FulfillRequest_MinimumGas() (gas: 202944) FunctionsClient_HandleOracleFulfillment:test_HandleOracleFulfillment_RevertIfNotRouter() (gas: 14623) FunctionsClient_HandleOracleFulfillment:test_HandleOracleFulfillment_Success() (gas: 22923) FunctionsClient__SendRequest:test__SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 55059) -FunctionsCoordinator_Constructor:test_Constructor_Success() (gas: 11984) +FunctionsCoordinator_Constructor:test_Constructor_Success() (gas: 12006) FunctionsCoordinator_GetDONPublicKey:test_GetDONPublicKey_RevertIfEmpty() (gas: 15334) -FunctionsCoordinator_GetDONPublicKey:test_GetDONPublicKey_Success() (gas: 106496) +FunctionsCoordinator_GetDONPublicKey:test_GetDONPublicKey_Success() (gas: 106506) FunctionsCoordinator_GetThresholdPublicKey:test_GetThresholdPublicKey_RevertIfEmpty() (gas: 15313) -FunctionsCoordinator_GetThresholdPublicKey:test_GetThresholdPublicKey_Success() (gas: 656556) +FunctionsCoordinator_GetThresholdPublicKey:test_GetThresholdPublicKey_Success() (gas: 656362) FunctionsCoordinator_SetDONPublicKey:test_SetDONPublicKey_RevertNotOwner() (gas: 20364) -FunctionsCoordinator_SetDONPublicKey:test_SetDONPublicKey_Success() (gas: 101275) +FunctionsCoordinator_SetDONPublicKey:test_SetDONPublicKey_Success() (gas: 101285) FunctionsCoordinator_SetThresholdPublicKey:test_SetThresholdPublicKey_RevertNotOwner() (gas: 13892) -FunctionsCoordinator_SetThresholdPublicKey:test_SetThresholdPublicKey_Success() (gas: 651248) +FunctionsCoordinator_SetThresholdPublicKey:test_SetThresholdPublicKey_Success() (gas: 651054) FunctionsCoordinator_StartRequest:test_StartRequest_RevertIfNotRouter() (gas: 22703) -FunctionsCoordinator_StartRequest:test_StartRequest_Success() (gas: 107681) +FunctionsCoordinator_StartRequest:test_StartRequest_Success() (gas: 108848) FunctionsCoordinator__IsTransmitter:test__IsTransmitter_SuccessFound() (gas: 18957) FunctionsCoordinator__IsTransmitter:test__IsTransmitter_SuccessNotFound() (gas: 19690) FunctionsRequest_DEFAULT_BUFFER_SIZE:test_DEFAULT_BUFFER_SIZE() (gas: 246) FunctionsRequest_EncodeCBOR:test_EncodeCBOR_Success() (gas: 223) FunctionsRequest_REQUEST_DATA_VERSION:test_REQUEST_DATA_VERSION() (gas: 225) FunctionsRouter_Constructor:test_Constructor_Success() (gas: 12007) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 169900) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 160227) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 174021) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 164352) FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidCommitment() (gas: 38115) FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidRequestId() (gas: 35238) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 178373) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 182497) FunctionsRouter_Fulfill:test_Fulfill_RevertIfNotCommittedCoordinator() (gas: 28086) -FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 153924) -FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 296712) -FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 310327) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2484946) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 515433) +FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 158041) +FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 323262) +FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 336879) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2512144) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 542628) FunctionsRouter_GetAdminFee:test_GetAdminFee_Success() (gas: 17983) FunctionsRouter_GetAllowListId:test_GetAllowListId_Success() (gas: 12904) FunctionsRouter_GetConfig:test_GetConfig_Success() (gas: 37159) @@ -71,15 +80,15 @@ FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotNe FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_RevertIfNotOwner() (gas: 23392) FunctionsRouter_ProposeContractsUpdate:test_ProposeContractsUpdate_Success() (gas: 118479) FunctionsRouter_SendRequest:test_SendRequest_RevertIfConsumerNotAllowed() (gas: 59347) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfDuplicateRequestId() (gas: 192799) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfDuplicateRequestId() (gas: 193436) FunctionsRouter_SendRequest:test_SendRequest_RevertIfEmptyData() (gas: 29426) FunctionsRouter_SendRequest:test_SendRequest_RevertIfIncorrectDonId() (gas: 57925) -FunctionsRouter_SendRequest:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 186299) +FunctionsRouter_SendRequest:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 186932) FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 50947) FunctionsRouter_SendRequest:test_SendRequest_RevertIfInvalidDonId() (gas: 25082) FunctionsRouter_SendRequest:test_SendRequest_RevertIfNoSubscription() (gas: 29132) FunctionsRouter_SendRequest:test_SendRequest_RevertIfPaused() (gas: 34291) -FunctionsRouter_SendRequest:test_SendRequest_Success() (gas: 285026) +FunctionsRouter_SendRequest:test_SendRequest_Success() (gas: 286243) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfConsumerNotAllowed() (gas: 65843) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfEmptyData() (gas: 36012) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfIncorrectDonId() (gas: 29896) @@ -87,8 +96,8 @@ FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalid FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfInvalidDonId() (gas: 27503) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfNoSubscription() (gas: 35717) FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_RevertIfPaused() (gas: 40810) -FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_Success() (gas: 291595) -FunctionsRouter_SendRequestToProposed:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 192791) +FunctionsRouter_SendRequestToProposed:test_SendRequestToProposed_Success() (gas: 292812) +FunctionsRouter_SendRequestToProposed:test_SendRequest_RevertIfInsufficientSubscriptionBalance() (gas: 193424) FunctionsRouter_SetAllowListId:test_SetAllowListId_Success() (gas: 30688) FunctionsRouter_SetAllowListId:test_UpdateConfig_RevertIfNotOwner() (gas: 13403) FunctionsRouter_Unpause:test_Unpause_RevertIfNotOwner() (gas: 13293) @@ -101,7 +110,7 @@ FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOw FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfPaused() (gas: 60987) FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderBecomesBlocked() (gas: 94677) FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_RevertIfSenderIsNotNewOwner() (gas: 62693) -FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_Success() (gas: 214560) +FunctionsSubscriptions_AcceptSubscriptionOwnerTransfer:test_AcceptSubscriptionOwnerTransfer_Success() (gas: 215197) FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumers() (gas: 137893) FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfMaximumConsumersAfterConfigUpdate() (gas: 164837) FunctionsSubscriptions_AddConsumer:test_AddConsumer_RevertIfNoSubscription() (gas: 12946) @@ -113,7 +122,7 @@ FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNoSubs FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotAllowedSender() (gas: 57885) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfNotSubscriptionOwner() (gas: 89272) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPaused() (gas: 20148) -FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 193688) +FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_RevertIfPendingRequests() (gas: 194325) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitAllBalanceAsDeposit() (gas: 114506) FunctionsSubscriptions_CancelSubscription:test_CancelSubscription_SuccessForfeitSomeBalanceAsDeposit() (gas: 125832) FunctionsSubscriptions_CancelSubscription_ReceiveDeposit:test_CancelSubscription_SuccessRecieveDeposit() (gas: 74973) @@ -133,8 +142,8 @@ FunctionsSubscriptions_GetTotalBalance:test_GetTotalBalance_Success() (gas: 1501 FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata(uint96) (runs: 256, μ: 43685, ~: 45548) FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96) (runs: 256, μ: 46197, ~: 48060) FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink(uint96) (runs: 256, μ: 14295, ~: 14295) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused(uint96) (runs: 256, μ: 51089, ~: 53040) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 86057, ~: 89604) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused(uint96) (runs: 256, μ: 51000, ~: 53040) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 85879, ~: 89604) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfAmountMoreThanBalance() (gas: 20745) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfBalanceInvariant() (gas: 189) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfNoAmount() (gas: 15638) @@ -146,7 +155,7 @@ FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_Reve FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_Success() (gas: 54867) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessDeletesSubscription() (gas: 49607) FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessSubOwnerRefunded() (gas: 50896) -FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessWhenRequestInFlight() (gas: 164303) +FunctionsSubscriptions_OwnerCancelSubscription:test_OwnerCancelSubscription_SuccessWhenRequestInFlight() (gas: 164812) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfAmountMoreThanBalance() (gas: 17924) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfBalanceInvariant() (gas: 210) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_RevertIfNotOwner() (gas: 15555) @@ -155,7 +164,7 @@ FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessIfRecipientAddres FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessPaysRecipient() (gas: 54413) FunctionsSubscriptions_OwnerWithdraw:test_OwnerWithdraw_SuccessSetsBalanceToZero() (gas: 37790) FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessFalseIfNoPendingRequests() (gas: 14981) -FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessTrueIfPendingRequests() (gas: 175857) +FunctionsSubscriptions_PendingRequestExists:test_PendingRequestExists_SuccessTrueIfPendingRequests() (gas: 176494) FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfEmptyNewOwner() (gas: 27611) FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfInvalidNewOwner() (gas: 57709) FunctionsSubscriptions_ProposeSubscriptionOwnerTransfer:test_ProposeSubscriptionOwnerTransfer_RevertIfNoSubscription() (gas: 15001) @@ -171,7 +180,7 @@ FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNoSubscription FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotAllowedSender() (gas: 57800) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfNotSubscriptionOwner() (gas: 87208) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPaused() (gas: 18049) -FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPendingRequests() (gas: 191221) +FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_RevertIfPendingRequests() (gas: 191858) FunctionsSubscriptions_RemoveConsumer:test_RemoveConsumer_Success() (gas: 41979) FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNoSubscription() (gas: 12891) FunctionsSubscriptions_SetFlags:test_SetFlags_RevertIfNotOwner() (gas: 15684) @@ -209,5 +218,5 @@ Gas_AcceptTermsOfService:test_AcceptTermsOfService_Gas() (gas: 84675) Gas_AddConsumer:test_AddConsumer_Gas() (gas: 79087) Gas_CreateSubscription:test_CreateSubscription_Gas() (gas: 73375) Gas_FundSubscription:test_FundSubscription_Gas() (gas: 38546) -Gas_SendRequest:test_SendRequest_MaximumGas() (gas: 964214) -Gas_SendRequest:test_SendRequest_MinimumGas() (gas: 156934) \ No newline at end of file +Gas_SendRequest:test_SendRequest_MaximumGas() (gas: 979631) +Gas_SendRequest:test_SendRequest_MinimumGas() (gas: 157578) \ No newline at end of file diff --git a/contracts/src/v0.8/functions/dev/v1_X/ChainSpecificUtil.sol b/contracts/src/v0.8/functions/dev/v1_X/ChainSpecificUtil.sol new file mode 100644 index 00000000000..f0eec19db24 --- /dev/null +++ b/contracts/src/v0.8/functions/dev/v1_X/ChainSpecificUtil.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {ArbGasInfo} from "../../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol"; +import {OVM_GasPriceOracle} from "../../../vendor/@eth-optimism/contracts/v0.8.9/contracts/L2/predeploys/OVM_GasPriceOracle.sol"; + +/// @dev A library that abstracts out opcodes that behave differently across chains. +/// @dev The methods below return values that are pertinent to the given chain. +library ChainSpecificUtil { + // ------------ Start Arbitrum Constants ------------ + + /// @dev ARBGAS_ADDR is the address of the ArbGasInfo precompile on Arbitrum. + /// @dev reference: https://github.com/OffchainLabs/nitro/blob/v2.0.14/contracts/src/precompiles/ArbGasInfo.sol#L10 + address private constant ARBGAS_ADDR = address(0x000000000000000000000000000000000000006C); + ArbGasInfo private constant ARBGAS = ArbGasInfo(ARBGAS_ADDR); + + uint256 private constant ARB_MAINNET_CHAIN_ID = 42161; + uint256 private constant ARB_GOERLI_TESTNET_CHAIN_ID = 421613; + uint256 private constant ARB_SEPOLIA_TESTNET_CHAIN_ID = 421614; + + // ------------ End Arbitrum Constants ------------ + + // ------------ Start Optimism Constants ------------ + /// @dev L1_FEE_DATA_PADDING includes 35 bytes for L1 data padding for Optimism + bytes internal constant L1_FEE_DATA_PADDING = + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + /// @dev OVM_GASPRICEORACLE_ADDR is the address of the OVM_GasPriceOracle precompile on Optimism. + /// @dev reference: https://community.optimism.io/docs/developers/build/transaction-fees/#estimating-the-l1-data-fee + address private constant OVM_GASPRICEORACLE_ADDR = address(0x420000000000000000000000000000000000000F); + OVM_GasPriceOracle private constant OVM_GASPRICEORACLE = OVM_GasPriceOracle(OVM_GASPRICEORACLE_ADDR); + + uint256 private constant OP_MAINNET_CHAIN_ID = 10; + uint256 private constant OP_GOERLI_CHAIN_ID = 420; + uint256 private constant OP_SEPOLIA_CHAIN_ID = 11155420; + + /// @dev Base is a OP stack based rollup and follows the same L1 pricing logic as Optimism. + uint256 private constant BASE_MAINNET_CHAIN_ID = 8453; + uint256 private constant BASE_GOERLI_CHAIN_ID = 84531; + uint256 private constant BASE_SEPOLIA_CHAIN_ID = 84532; + + // ------------ End Optimism Constants ------------ + + /// @notice Returns the L1 fees in wei that will be paid for the current transaction, given any calldata + /// @notice for the current transaction. + /// @notice When on a known Arbitrum chain, it uses ArbGas.getCurrentTxL1GasFees to get the fees. + /// @notice On Arbitrum, the provided calldata is not used to calculate the fees. + /// @notice On Optimism, the provided calldata is passed to the OVM_GasPriceOracle predeploy + /// @notice and getL1Fee is called to get the fees. + function _getCurrentTxL1GasFees(bytes memory txCallData) internal view returns (uint256 l1FeeWei) { + uint256 chainid = block.chainid; + if (_isArbitrumChainId(chainid)) { + return ARBGAS.getCurrentTxL1GasFees(); + } else if (_isOptimismChainId(chainid)) { + return OVM_GASPRICEORACLE.getL1Fee(bytes.concat(txCallData, L1_FEE_DATA_PADDING)); + } + return 0; + } + + /// @notice Return true if and only if the provided chain ID is an Arbitrum chain ID. + function _isArbitrumChainId(uint256 chainId) internal pure returns (bool) { + return + chainId == ARB_MAINNET_CHAIN_ID || + chainId == ARB_GOERLI_TESTNET_CHAIN_ID || + chainId == ARB_SEPOLIA_TESTNET_CHAIN_ID; + } + + /// @notice Return true if and only if the provided chain ID is an Optimism (or Base) chain ID. + /// @notice Note that optimism chain id's are also OP stack chain id's. + function _isOptimismChainId(uint256 chainId) internal pure returns (bool) { + return + chainId == OP_MAINNET_CHAIN_ID || + chainId == OP_GOERLI_CHAIN_ID || + chainId == OP_SEPOLIA_CHAIN_ID || + chainId == BASE_MAINNET_CHAIN_ID || + chainId == BASE_GOERLI_CHAIN_ID || + chainId == BASE_SEPOLIA_CHAIN_ID; + } +} diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol index adc6218733f..bf43ead8d72 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol @@ -10,6 +10,8 @@ import {FunctionsResponse} from "./libraries/FunctionsResponse.sol"; import {SafeCast} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/math/SafeCast.sol"; +import {ChainSpecificUtil} from "./ChainSpecificUtil.sol"; + /// @title Functions Billing contract /// @notice Contract that calculates payment from users to the nodes of the Decentralized Oracle Network (DON). abstract contract FunctionsBilling is Routable, IFunctionsBilling { @@ -123,10 +125,10 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { return uint256(weiPerUnitLink); } - function _getJuelsPerGas(uint256 gasPriceWei) private view returns (uint96) { - // (1e18 juels/link) * (wei/gas) / (wei/link) = juels per gas + function _getJuelsFromWei(uint256 amountWei) private view returns (uint96) { + // (1e18 juels/link) * wei / (wei/link) = juels // There are only 1e9*1e18 = 1e27 juels in existence, should not exceed uint96 (2^96 ~ 7e28) - return SafeCast.toUint96((1e18 * gasPriceWei) / getWeiPerUnitLink()); + return SafeCast.toUint96((1e18 * amountWei) / getWeiPerUnitLink()); } // ================================================================ @@ -159,8 +161,6 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { uint72 donFee, uint72 adminFee ) internal view returns (uint96) { - uint256 executionGas = s_config.gasOverheadBeforeCallback + s_config.gasOverheadAfterCallback + callbackGasLimit; - // If gas price is less than the minimum fulfillment gas price, override to using the minimum if (gasPriceWei < s_config.minimumEstimateGasPriceWei) { gasPriceWei = s_config.minimumEstimateGasPriceWei; @@ -170,11 +170,13 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { ((gasPriceWei * s_config.fulfillmentGasPriceOverEstimationBP) / 10_000); /// @NOTE: Basis Points are 1/100th of 1%, divide by 10_000 to bring back to original units - uint96 juelsPerGas = _getJuelsPerGas(gasPriceWithOverestimation); - uint256 estimatedGasReimbursement = juelsPerGas * executionGas; - uint96 fees = uint96(donFee) + uint96(adminFee); + uint256 executionGas = s_config.gasOverheadBeforeCallback + s_config.gasOverheadAfterCallback + callbackGasLimit; + uint256 l1FeeWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data); + uint96 estimatedGasReimbursementJuels = _getJuelsFromWei((gasPriceWithOverestimation * executionGas) + l1FeeWei); + + uint96 feesJuels = uint96(donFee) + uint96(adminFee); - return SafeCast.toUint96(estimatedGasReimbursement + fees); + return estimatedGasReimbursementJuels + feesJuels; } // ================================================================ @@ -248,6 +250,7 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { /// @param requestId identifier for the request that was generated by the Registry in the beginBilling commitment /// @param response response data from DON consensus /// @param err error from DON consensus + /// @param reportBatchSize the number of fulfillments in the transmitter's report /// @return result fulfillment result /// @dev Only callable by a node that has been approved on the Coordinator /// @dev simulated offchain to determine if sufficient balance is present to fulfill the request @@ -256,21 +259,22 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { bytes memory response, bytes memory err, bytes memory onchainMetadata, - bytes memory /* offchainMetadata TODO: use in getDonFee() for dynamic billing */ + bytes memory /* offchainMetadata TODO: use in getDonFee() for dynamic billing */, + uint8 reportBatchSize ) internal returns (FunctionsResponse.FulfillResult) { FunctionsResponse.Commitment memory commitment = abi.decode(onchainMetadata, (FunctionsResponse.Commitment)); - uint96 juelsPerGas = _getJuelsPerGas(tx.gasprice); + uint256 gasOverheadWei = (commitment.gasOverheadBeforeCallback + commitment.gasOverheadAfterCallback) * tx.gasprice; + uint256 l1FeeShareWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data) / reportBatchSize; // Gas overhead without callback - uint96 gasOverheadJuels = juelsPerGas * - (commitment.gasOverheadBeforeCallback + commitment.gasOverheadAfterCallback); + uint96 gasOverheadJuels = _getJuelsFromWei(gasOverheadWei + l1FeeShareWei); // The Functions Router will perform the callback to the client contract (FunctionsResponse.FulfillResult resultCode, uint96 callbackCostJuels) = _getRouter().fulfill( response, err, - juelsPerGas, - gasOverheadJuels + commitment.donFee, // costWithoutFulfillment + _getJuelsFromWei(tx.gasprice), // Juels Per Gas conversion rate + gasOverheadJuels + commitment.donFee, // cost without callback or admin fee, those will be added by the Router msg.sender, commitment ); diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol index eb0d954ae02..2caab41c746 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol @@ -156,7 +156,14 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli // Bounded by "MaxRequestBatchSize" on the Job's ReportingPluginConfig for (uint256 i = 0; i < requestIds.length; ++i) { FunctionsResponse.FulfillResult result = FunctionsResponse.FulfillResult( - _fulfillAndBill(requestIds[i], results[i], errors[i], onchainMetadata[i], offchainMetadata[i]) + _fulfillAndBill( + requestIds[i], + results[i], + errors[i], + onchainMetadata[i], + offchainMetadata[i], + uint8(requestIds.length) // will not exceed "MaxRequestBatchSize" on the Job's ReportingPluginConfig + ) ); // Emit on successfully processing the fulfillment diff --git a/contracts/src/v0.8/functions/tests/v1_X/ChainSpecificUtil.t.sol b/contracts/src/v0.8/functions/tests/v1_X/ChainSpecificUtil.t.sol new file mode 100644 index 00000000000..5384a66d912 --- /dev/null +++ b/contracts/src/v0.8/functions/tests/v1_X/ChainSpecificUtil.t.sol @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import {BaseTest} from "./BaseTest.t.sol"; +import {FunctionsClient} from "../../dev/v1_X/FunctionsClient.sol"; +import {FunctionsRouter} from "../../dev/v1_X/FunctionsRouter.sol"; +import {FunctionsSubscriptions} from "../../dev/v1_X/FunctionsSubscriptions.sol"; +import {FunctionsRequest} from "../../dev/v1_X/libraries/FunctionsRequest.sol"; +import {FunctionsResponse} from "../../dev/v1_X/libraries/FunctionsResponse.sol"; + +import {FunctionsFulfillmentSetup} from "./Setup.t.sol"; + +import {ArbGasInfo} from "../../../vendor/@arbitrum/nitro-contracts/src/precompiles/ArbGasInfo.sol"; +import {OVM_GasPriceOracle} from "../../../vendor/@eth-optimism/contracts/v0.8.9/contracts/L2/predeploys/OVM_GasPriceOracle.sol"; + +/// @notice #_getCurrentTxL1GasFees Arbitrum +/// @dev Arbitrum gas formula = L2 Gas Price * (Gas used on L2 + Extra Buffer for L1 cost) +/// @dev where Extra Buffer for L1 cost = (L1 Estimated Cost / L2 Gas Price) +contract ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum is FunctionsFulfillmentSetup { + address private constant ARBGAS_ADDR = address(0x000000000000000000000000000000000000006C); + uint256 private constant L1_FEE_WEI = 15_818_209_764_247; + + uint96 l1FeeJuels = uint96((1e18 * L1_FEE_WEI) / uint256(LINK_ETH_RATE)); + + function setUp() public virtual override { + vm.mockCall(ARBGAS_ADDR, abi.encodeWithSelector(ArbGasInfo.getCurrentTxL1GasFees.selector), abi.encode(L1_FEE_WEI)); + } + + function test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() public { + // Set the chainID + vm.chainId(42161); + + // Setup sends and fulfills request #1 + FunctionsFulfillmentSetup.setUp(); + + // Check request cost estimate + uint96 expectedEstimatedTotalCostJuels = _getExpectedCostEstimate(s_requests[1].requestData.callbackGasLimit) + + l1FeeJuels; + assertEq(s_requests[1].commitment.estimatedTotalCostJuels, expectedEstimatedTotalCostJuels); + + // Check response actual cost + uint96 expectedTotalCostJuels = _getExpectedCost(5416) + l1FeeJuels; + assertEq(s_responses[1].totalCostJuels, expectedTotalCostJuels); + } + + function test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() public { + // Set the chainID + vm.chainId(421613); + + // Setup sends and fulfills request #1 + FunctionsFulfillmentSetup.setUp(); + + // Check request cost estimate + uint96 expectedEstimatedTotalCostJuels = _getExpectedCostEstimate(s_requests[1].requestData.callbackGasLimit) + + l1FeeJuels; + assertEq(s_requests[1].commitment.estimatedTotalCostJuels, expectedEstimatedTotalCostJuels); + + // Check response actual cost + uint96 expectedTotalCostJuels = _getExpectedCost(5416) + l1FeeJuels; + assertEq(s_responses[1].totalCostJuels, expectedTotalCostJuels); + } + + function test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() public { + // Set the chainID + vm.chainId(421614); + + // Setup sends and fulfills request #1 + FunctionsFulfillmentSetup.setUp(); + + // Check request cost estimate + uint96 expectedEstimatedTotalCostJuels = _getExpectedCostEstimate(s_requests[1].requestData.callbackGasLimit) + + l1FeeJuels; + assertEq(s_requests[1].commitment.estimatedTotalCostJuels, expectedEstimatedTotalCostJuels); + + // Check response actual cost + uint96 expectedTotalCostJuels = _getExpectedCost(5416) + l1FeeJuels; + assertEq(s_responses[1].totalCostJuels, expectedTotalCostJuels); + } +} + +/// @notice #_getCurrentTxL1GasFees Optimism +/// @dev Optimism gas formula = ((l2_base_fee + l2_priority_fee) * l2_gas_used) + L1 data fee +/// @dev where L1 data fee = l1_gas_price * ((count_zero_bytes(tx_data) * 4 + count_non_zero_bytes(tx_data) * 16) + fixed_overhead + noncalldata_gas) * dynamic_overhead +contract ChainSpecificUtil__getCurrentTxL1GasFees_Optimism is FunctionsFulfillmentSetup { + address private constant OVM_GASPRICEORACLE_ADDR = address(0x420000000000000000000000000000000000000F); + uint256 private constant L1_FEE_WEI = 15_818_209_764_247; + + uint96 l1FeeJuels = uint96((1e18 * L1_FEE_WEI) / uint256(LINK_ETH_RATE)); + + function setUp() public virtual override { + vm.mockCall( + OVM_GASPRICEORACLE_ADDR, + abi.encodeWithSelector(OVM_GasPriceOracle.getL1Fee.selector), + abi.encode(L1_FEE_WEI) + ); + } + + function test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() public { + // Set the chainID + vm.chainId(10); + + // Setup sends and fulfills request #1 + FunctionsFulfillmentSetup.setUp(); + + // Check request cost estimate + uint96 expectedEstimatedTotalCostJuels = _getExpectedCostEstimate(s_requests[1].requestData.callbackGasLimit) + + l1FeeJuels; + assertEq(s_requests[1].commitment.estimatedTotalCostJuels, expectedEstimatedTotalCostJuels); + + // Check response actual cost + uint96 expectedTotalCostJuels = _getExpectedCost(5416) + l1FeeJuels; + assertEq(s_responses[1].totalCostJuels, expectedTotalCostJuels); + } + + function test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() public { + // Set the chainID + vm.chainId(420); + + // Setup sends and fulfills request #1 + FunctionsFulfillmentSetup.setUp(); + + // Check request cost estimate + uint96 expectedEstimatedTotalCostJuels = _getExpectedCostEstimate(s_requests[1].requestData.callbackGasLimit) + + l1FeeJuels; + assertEq(s_requests[1].commitment.estimatedTotalCostJuels, expectedEstimatedTotalCostJuels); + + // Check response actual cost + uint96 expectedTotalCostJuels = _getExpectedCost(5416) + l1FeeJuels; + assertEq(s_responses[1].totalCostJuels, expectedTotalCostJuels); + } + + function test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() public { + // Set the chainID + vm.chainId(11155420); + + // Setup sends and fulfills request #1 + FunctionsFulfillmentSetup.setUp(); + + // Check request cost estimate + uint96 expectedEstimatedTotalCostJuels = _getExpectedCostEstimate(s_requests[1].requestData.callbackGasLimit) + + l1FeeJuels; + assertEq(s_requests[1].commitment.estimatedTotalCostJuels, expectedEstimatedTotalCostJuels); + + // Check response actual cost + uint96 expectedTotalCostJuels = _getExpectedCost(5416) + l1FeeJuels; + assertEq(s_responses[1].totalCostJuels, expectedTotalCostJuels); + } +} + +/// @notice #_getCurrentTxL1GasFees Base +/// @dev Base gas formula uses Optimism formula = ((l2_base_fee + l2_priority_fee) * l2_gas_used) + L1 data fee +/// @dev where L1 data fee = l1_gas_price * ((count_zero_bytes(tx_data) * 4 + count_non_zero_bytes(tx_data) * 16) + fixed_overhead + noncalldata_gas) * dynamic_overhead +contract ChainSpecificUtil__getCurrentTxL1GasFees_Base is FunctionsFulfillmentSetup { + address private constant OVM_GASPRICEORACLE_ADDR = address(0x420000000000000000000000000000000000000F); + uint256 private constant L1_FEE_WEI = 15_818_209_764_247; + + uint96 l1FeeJuels = uint96((1e18 * L1_FEE_WEI) / uint256(LINK_ETH_RATE)); + + function setUp() public virtual override { + vm.mockCall( + OVM_GASPRICEORACLE_ADDR, + abi.encodeWithSelector(OVM_GasPriceOracle.getL1Fee.selector), + abi.encode(L1_FEE_WEI) + ); + } + + function test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() public { + // Set the chainID + vm.chainId(8453); + + // Setup sends and fulfills request #1 + FunctionsFulfillmentSetup.setUp(); + + // Check request cost estimate + uint96 expectedEstimatedTotalCostJuels = _getExpectedCostEstimate(s_requests[1].requestData.callbackGasLimit) + + l1FeeJuels; + assertEq(s_requests[1].commitment.estimatedTotalCostJuels, expectedEstimatedTotalCostJuels); + + // Check response actual cost + uint96 expectedTotalCostJuels = _getExpectedCost(5416) + l1FeeJuels; + assertEq(s_responses[1].totalCostJuels, expectedTotalCostJuels); + } + + function test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() public { + // Set the chainID + vm.chainId(84531); + + // Setup sends and fulfills request #1 + FunctionsFulfillmentSetup.setUp(); + + // Check request cost estimate + uint96 expectedEstimatedTotalCostJuels = _getExpectedCostEstimate(s_requests[1].requestData.callbackGasLimit) + + l1FeeJuels; + assertEq(s_requests[1].commitment.estimatedTotalCostJuels, expectedEstimatedTotalCostJuels); + + // Check response actual cost + uint96 expectedTotalCostJuels = _getExpectedCost(5416) + l1FeeJuels; + assertEq(s_responses[1].totalCostJuels, expectedTotalCostJuels); + } + + function test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() public { + // Set the chainID + vm.chainId(84532); + + // Setup sends and fulfills request #1 + FunctionsFulfillmentSetup.setUp(); + + // Check request cost estimate + uint96 expectedEstimatedTotalCostJuels = _getExpectedCostEstimate(s_requests[1].requestData.callbackGasLimit) + + l1FeeJuels; + assertEq(s_requests[1].commitment.estimatedTotalCostJuels, expectedEstimatedTotalCostJuels); + + // Check response actual cost + uint96 expectedTotalCostJuels = _getExpectedCost(5416) + l1FeeJuels; + assertEq(s_responses[1].totalCostJuels, expectedTotalCostJuels); + } +} diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsCoordinator.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsCoordinator.t.sol index 7166add19fe..f6d3d41e632 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsCoordinator.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsCoordinator.t.sol @@ -10,7 +10,6 @@ import {Routable} from "../../dev/v1_X/Routable.sol"; import {BaseTest} from "./BaseTest.t.sol"; import {FunctionsRouterSetup, FunctionsDONSetup, FunctionsSubscriptionSetup} from "./Setup.t.sol"; -import "forge-std/console.sol"; /// @notice #constructor contract FunctionsCoordinator_Constructor is FunctionsRouterSetup { diff --git a/contracts/src/v0.8/functions/tests/v1_X/Gas.t.sol b/contracts/src/v0.8/functions/tests/v1_X/Gas.t.sol index 55ab3810b41..f2d7af54e4f 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/Gas.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/Gas.t.sol @@ -154,14 +154,6 @@ contract Gas_SendRequest is FunctionsSubscriptionSetup { /// @notice #fulfillRequest contract FunctionsClient_FulfillRequest is FunctionsClientRequestSetup { - struct Report { - bytes32[] rs; - bytes32[] ss; - bytes32 vs; - bytes report; - bytes32[3] reportContext; - } - mapping(uint256 reportNumber => Report) s_reports; FunctionsClientTestHelper s_functionsClientWithMaximumReturnData; diff --git a/contracts/src/v0.8/functions/tests/v1_X/Setup.t.sol b/contracts/src/v0.8/functions/tests/v1_X/Setup.t.sol index 0c08fd20cd3..97418958bc2 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/Setup.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/Setup.t.sol @@ -225,6 +225,14 @@ contract FunctionsSubscriptionSetup is FunctionsClientSetup { /// @notice Set up to initate a minimal request and store it in s_requests[1] contract FunctionsClientRequestSetup is FunctionsSubscriptionSetup { + struct Report { + bytes32[] rs; + bytes32[] ss; + bytes32 vs; + bytes report; + bytes32[3] reportContext; + } + struct RequestData { string sourceCode; bytes secrets; @@ -240,6 +248,12 @@ contract FunctionsClientRequestSetup is FunctionsSubscriptionSetup { mapping(uint256 requestNumber => Request) s_requests; + struct Response { + uint96 totalCostJuels; + } + + mapping(uint256 requestNumber => Response) s_responses; + uint96 s_fulfillmentRouterOwnerBalance = 0; uint96 s_fulfillmentCoordinatorBalance = 0; @@ -255,7 +269,24 @@ contract FunctionsClientRequestSetup is FunctionsSubscriptionSetup { _sendAndStoreRequest(1, sourceCode, secrets, args, bytesArgs, callbackGasLimit); } - function _getExpectedCost(uint256 gasUsed) internal view returns (uint96 totalCostJuels) { + /// @notice Predicts the estimated cost (maximum cost) of a request + /// @dev Meant only for Ethereum, does not add L2 chains' L1 fee + function _getExpectedCostEstimate(uint256 callbackGas) internal view returns (uint96) { + uint256 gasPrice = TX_GASPRICE_START < getCoordinatorConfig().minimumEstimateGasPriceWei + ? getCoordinatorConfig().minimumEstimateGasPriceWei + : TX_GASPRICE_START; + uint256 gasPriceWithOverestimation = gasPrice + + ((gasPrice * getCoordinatorConfig().fulfillmentGasPriceOverEstimationBP) / 10_000); + uint96 juelsPerGas = uint96((1e18 * gasPriceWithOverestimation) / uint256(LINK_ETH_RATE)); + uint96 gasOverheadJuels = juelsPerGas * + ((getCoordinatorConfig().gasOverheadBeforeCallback + getCoordinatorConfig().gasOverheadAfterCallback)); + uint96 callbackGasCostJuels = uint96(juelsPerGas * callbackGas); + return gasOverheadJuels + s_donFee + s_adminFee + callbackGasCostJuels; + } + + /// @notice Predicts the actual cost of a request + /// @dev Meant only for Ethereum, does not add L2 chains' L1 fee + function _getExpectedCost(uint256 gasUsed) internal view returns (uint96) { uint96 juelsPerGas = uint96((1e18 * TX_GASPRICE_START) / uint256(LINK_ETH_RATE)); uint96 gasOverheadJuels = juelsPerGas * (getCoordinatorConfig().gasOverheadBeforeCallback + getCoordinatorConfig().gasOverheadAfterCallback); @@ -400,7 +431,7 @@ contract FunctionsClientRequestSetup is FunctionsSubscriptionSetup { bytes memory report, bytes32[3] memory reportContext, uint256[] memory signerPrivateKeys - ) internal pure returns (bytes32[] memory rawRs, bytes32[] memory rawSs, bytes32 rawVs) { + ) internal pure returns (bytes32[] memory, bytes32[] memory, bytes32) { bytes32[] memory rs = new bytes32[](signerPrivateKeys.length); bytes32[] memory ss = new bytes32[](signerPrivateKeys.length); bytes memory vs = new bytes(signerPrivateKeys.length); @@ -417,13 +448,35 @@ contract FunctionsClientRequestSetup is FunctionsSubscriptionSetup { return (rs, ss, bytes32(vs)); } + function _buildAndSignReport( + uint256[] memory requestNumberKeys, + string[] memory results, + bytes[] memory errors + ) internal view returns (Report memory) { + (bytes memory report, bytes32[3] memory reportContext) = _buildReport(requestNumberKeys, results, errors); + + // Sign the report + // Need at least 3 signers to fulfill minimum number of: (configInfo.n + configInfo.f) / 2 + 1 + uint256[] memory signerPrivateKeys = new uint256[](3); + signerPrivateKeys[0] = NOP_SIGNER_PRIVATE_KEY_1; + signerPrivateKeys[1] = NOP_SIGNER_PRIVATE_KEY_2; + signerPrivateKeys[2] = NOP_SIGNER_PRIVATE_KEY_3; + (bytes32[] memory rawRs, bytes32[] memory rawSs, bytes32 rawVs) = _signReport( + report, + reportContext, + signerPrivateKeys + ); + + return Report({report: report, reportContext: reportContext, rs: rawRs, ss: rawSs, vs: rawVs}); + } + /// @notice Provide a response from the DON to fulfill one or more requests and store the updated balances of the DON & Admin /// @param requestNumberKeys - One or more requestNumberKeys that were used to store the request in `s_requests` of the requests, that will be added to the report /// @param results - The result that will be sent to the consumer contract's callback. For each index, e.g. result[index] or errors[index], only one of should be filled. /// @param errors - The error that will be sent to the consumer contract's callback. For each index, e.g. result[index] or errors[index], only one of should be filled. /// @param transmitter - The address that will send the `.report` transaction /// @param expectedToSucceed - Boolean representing if the report transmission is expected to produce a RequestProcessed event for every fulfillment. If not, we ignore retrieving the event log. - /// @param requestProcessedIndex - On a successful fulfillment the Router will emit a RequestProcessed event. To grab that event we must know the order at which this event was thrown in the report transmission lifecycle. This can change depending on the test setup (e.g. the Client contract gives an extra event during its callback) + /// @param requestProcessedStartIndex - On a successful fulfillment the Router will emit a RequestProcessed event. To grab that event we must know the order at which this event was thrown in the report transmission lifecycle. This can change depending on the test setup (e.g. the Client contract gives an extra event during its callback) /// @param transmitterGasToUse - Override the default amount of gas that the transmitter sends the `.report` transaction with function _reportAndStore( uint256[] memory requestNumberKeys, @@ -431,7 +484,7 @@ contract FunctionsClientRequestSetup is FunctionsSubscriptionSetup { bytes[] memory errors, address transmitter, bool expectedToSucceed, - uint8 requestProcessedIndex, + uint8 requestProcessedStartIndex, uint256 transmitterGasToUse ) internal { { @@ -440,19 +493,7 @@ contract FunctionsClientRequestSetup is FunctionsSubscriptionSetup { } } - (bytes memory report, bytes32[3] memory reportContext) = _buildReport(requestNumberKeys, results, errors); - - // Sign the report - // Need at least 3 signers to fulfill minimum number of: (configInfo.n + configInfo.f) / 2 + 1 - uint256[] memory signerPrivateKeys = new uint256[](3); - signerPrivateKeys[0] = NOP_SIGNER_PRIVATE_KEY_1; - signerPrivateKeys[1] = NOP_SIGNER_PRIVATE_KEY_2; - signerPrivateKeys[2] = NOP_SIGNER_PRIVATE_KEY_3; - (bytes32[] memory rawRs, bytes32[] memory rawSs, bytes32 rawVs) = _signReport( - report, - reportContext, - signerPrivateKeys - ); + Report memory r = _buildAndSignReport(requestNumberKeys, results, errors); // Send as transmitter vm.stopPrank(); @@ -461,20 +502,24 @@ contract FunctionsClientRequestSetup is FunctionsSubscriptionSetup { // Send report vm.recordLogs(); if (transmitterGasToUse > 0) { - s_functionsCoordinator.transmit{gas: transmitterGasToUse}(reportContext, report, rawRs, rawSs, rawVs); + s_functionsCoordinator.transmit{gas: transmitterGasToUse}(r.reportContext, r.report, r.rs, r.ss, r.vs); } else { - s_functionsCoordinator.transmit(reportContext, report, rawRs, rawSs, rawVs); + s_functionsCoordinator.transmit(r.reportContext, r.report, r.rs, r.ss, r.vs); } if (expectedToSucceed) { // Get actual cost from RequestProcessed event log (uint96 totalCostJuels, , , , , ) = abi.decode( - vm.getRecordedLogs()[requestProcessedIndex].data, + vm.getRecordedLogs()[requestProcessedStartIndex].data, (uint96, address, FunctionsResponse.FulfillResult, bytes, bytes, bytes) ); + // Store response of first request + // TODO: handle multiple requests + s_responses[requestNumberKeys[0]] = Response({totalCostJuels: totalCostJuels}); // Store profit amounts - s_fulfillmentRouterOwnerBalance += s_adminFee; + s_fulfillmentRouterOwnerBalance += s_adminFee * uint96(requestNumberKeys.length); // totalCostJuels = costWithoutCallbackJuels + adminFee + callbackGasCostJuels + // TODO: handle multiple requests s_fulfillmentCoordinatorBalance += totalCostJuels - s_adminFee; } diff --git a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorHarness.sol b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorHarness.sol index bc103fc3561..c1b6d5d0b14 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorHarness.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/testhelpers/FunctionsCoordinatorHarness.sol @@ -79,9 +79,10 @@ contract FunctionsCoordinatorHarness is FunctionsCoordinator { bytes memory response, bytes memory err, bytes memory onchainMetadata, - bytes memory offchainMetadata + bytes memory offchainMetadata, + uint8 reportBatchSize ) external returns (FunctionsResponse.FulfillResult) { - return super._fulfillAndBill(requestId, response, err, onchainMetadata, offchainMetadata); + return super._fulfillAndBill(requestId, response, err, onchainMetadata, offchainMetadata, reportBatchSize); } function disperseFeePool_HARNESS() external { diff --git a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go index ffe072fc657..b2e5ec4b09a 100644 --- a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go +++ b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go @@ -72,7 +72,7 @@ type FunctionsResponseRequestMeta struct { var FunctionsCoordinatorMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"linkToNativeFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPublicKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InconsistentReportData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoTransmittersSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouterOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReportInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustBeSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedPublicKeyChange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedRequestDataVersion\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CommitmentDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"callbackGasLimit\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"OracleResponse\",\"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\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"deleteCommitment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"gasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateCost\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getDONFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getThresholdPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracleWithdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"_f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"_offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"donPublicKey\",\"type\":\"bytes\"}],\"name\":\"setDONPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"thresholdPublicKey\",\"type\":\"bytes\"}],\"name\":\"setThresholdPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"availableBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"}],\"internalType\":\"structFunctionsResponse.RequestMeta\",\"name\":\"request\",\"type\":\"tuple\"}],\"name\":\"startRequest\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"transmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60c06040523480156200001157600080fd5b506040516200529938038062005299833981016040819052620000349162000474565b8282828260013380600081620000915760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c457620000c48162000140565b50505015156080526001600160a01b038116620000f457604051632530e88560e11b815260040160405180910390fd5b6001600160a01b0390811660a052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200013482620001eb565b50505050505062000633565b336001600160a01b038216036200019a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000088565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001f562000349565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160f01b026001600160f01b0364ffffffffff909216600160c81b0264ffffffffff60c81b196001600160481b03909416600160801b0293909316600160801b600160f01b031963ffffffff9586166c010000000000000000000000000263ffffffff60601b19978716680100000000000000000297909716600160401b600160801b0319998716640100000000026001600160401b0319909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e0830151610100840151909216600160e01b026001600160e01b0390921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906200033e9083906200057d565b60405180910390a150565b6200035362000355565b565b6000546001600160a01b03163314620003535760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000088565b80516001600160a01b0381168114620003c957600080fd5b919050565b60405161012081016001600160401b03811182821017156200040057634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff81168114620003c957600080fd5b80516001600160481b0381168114620003c957600080fd5b805164ffffffffff81168114620003c957600080fd5b805161ffff81168114620003c957600080fd5b80516001600160e01b0381168114620003c957600080fd5b60008060008385036101608112156200048c57600080fd5b6200049785620003b1565b935061012080601f1983011215620004ae57600080fd5b620004b8620003ce565b9150620004c86020870162000406565b8252620004d86040870162000406565b6020830152620004eb6060870162000406565b6040830152620004fe6080870162000406565b60608301526200051160a087016200041b565b60808301526200052460c0870162000433565b60a08301526200053760e0870162000449565b60c08301526101006200054c8188016200045c565b60e08401526200055e82880162000406565b90830152509150620005746101408501620003b1565b90509250925092565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151620005d060808401826001600160481b03169052565b5060a0830151620005ea60a084018264ffffffffff169052565b5060c08301516200060160c084018261ffff169052565b5060e08301516200061d60e08401826001600160e01b03169052565b506101009283015163ffffffff16919092015290565b60805160a051614c166200068360003960008181610845015281816109d301528181610ca601528181610f3a0152818161104501528181611830015261332c0152600061126e0152614c166000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806381ff7048116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610560578063e4ddcea614610573578063f2fde38b1461058957600080fd5b8063c3f909d4146103b0578063d227d24514610528578063d328a91e1461055857600080fd5b8063a631571e116100bd578063a631571e1461035d578063afcb95d71461037d578063b1dc65a41461039d57600080fd5b806381ff7048146102b557806385b214cf146103225780638da5cb5b1461033557600080fd5b806366316d8d116101455780637f15e1661161011f5780637f15e16614610285578063814118341461029857806381f1b938146102ad57600080fd5b806366316d8d1461026257806379ba5097146102755780637d4807871461027d57600080fd5b8063181f5a7711610176578063181f5a77146101ba5780632a905ccc1461020c57806359b5b7ac1461022e57600080fd5b8063083a5466146101925780631112dadc146101a7575b600080fd5b6101a56101a036600461361f565b61059c565b005b6101a56101b53660046137c8565b6105f1565b6101f66040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e312e300000000081525081565b60405161020391906138e2565b60405180910390f35b610214610841565b60405168ffffffffffffffffff9091168152602001610203565b61021461023c36600461398a565b50600854700100000000000000000000000000000000900468ffffffffffffffffff1690565b6101a5610270366004613a19565b6108d7565b6101a5610a90565b6101a5610b92565b6101a561029336600461361f565b610d92565b6102a0610de2565b6040516102039190613aa3565b6101f6610e51565b6102ff60015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610203565b6101a5610330366004613ab6565b610f22565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610203565b61037061036b366004613acf565b610fd4565b6040516102039190613c24565b604080516001815260006020820181905291810191909152606001610203565b6101a56103ab366004613c78565b611175565b61051b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810468ffffffffffffffffff166080830152790100000000000000000000000000000000000000000000000000810464ffffffffff1660a08301527e01000000000000000000000000000000000000000000000000000000000000900461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08301527c0100000000000000000000000000000000000000000000000000000000900490911661010082015290565b6040516102039190613d2f565b61053b610536366004613e1f565b61182c565b6040516bffffffffffffffffffffffff9091168152602001610203565b6101f661198c565b6101a561056e366004613f38565b6119e3565b61057b61240f565b604051908152602001610203565b6101a5610597366004614005565b612668565b6105a461267c565b60008190036105df576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105ec8284836140bb565b505050565b6105f96126ff565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff64ffffffffff909216790100000000000000000000000000000000000000000000000000027fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90941670010000000000000000000000000000000002939093167fffff0000000000000000000000000000ffffffffffffffffffffffffffffffff63ffffffff9586166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9787166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e08301516101008401519092167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f518486290610836908390613d2f565b60405180910390a150565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d291906141e1565b905090565b6108df612707565b806bffffffffffffffffffffffff166000036109195750336000908152600a60205260409020546bffffffffffffffffffffffff16610973565b336000908152600a60205260409020546bffffffffffffffffffffffff80831691161015610973576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906109a09084906bffffffffffffffffffffffff1661422d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506109f57f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b158015610a7457600080fd5b505af1158015610a88573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b9a6126ff565b610ba2612707565b6000610bac610de2565b905060005b8151811015610d8e576000600a6000848481518110610bd257610bd2614252565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d7d576000600a6000858581518110610c3157610c31614252565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610cc87f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610cf557610cf5614252565b6020026020010151836040518363ffffffff1660e01b8152600401610d4a92919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d6457600080fd5b505af1158015610d78573d6000803e3d6000fd5b505050505b50610d8781614281565b9050610bb1565b5050565b610d9a61267c565b6000819003610dd5576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105ec8284836140bb565b60606006805480602002602001604051908101604052809291908181526020018280548015610e4757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e1c575b5050505050905090565b6060600d8054610e6090614022565b9050600003610e9b576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610ea890614022565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed490614022565b8015610e475780601f10610ef657610100808354040283529160200191610e47565b820191906000526020600020905b815481529060010190602001808311610f0457509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f91576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f416906108369083815260200190565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461109c576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110ad6110a8836142b9565b6128b2565b90506110bf6060830160408401614005565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff3261110d60c0870160a088016143a6565b61111f61016088016101408901614005565b61112988806143c3565b61113b6101208b016101008c01614428565b60208b01356111516101008d0160e08e01614443565b8b60405161116799989796959493929190614460565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16040805160608101825260025480825260035460ff8082166020850152610100909104169282019290925290831461125c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f6e666967446967657374206d69736d6174636800000000000000000000006044820152606401610b0d565b61126a8b8b8b8b8b8b612d50565b60007f0000000000000000000000000000000000000000000000000000000000000000156112c7576002826020015183604001516112a89190614508565b6112b29190614550565b6112bd906001614508565b60ff1690506112dd565b60208201516112d7906001614508565b60ff1690505b888114611346576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610b0d565b8887146113af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f7369676e617475726573206f7574206f6620726567697374726174696f6e00006044820152606401610b0d565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113f2576113f2614572565b600281111561140357611403614572565b905250905060028160200151600281111561142057611420614572565b14801561146757506006816000015160ff168154811061144257611442614252565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b6114cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610b0d565b50505050506114da6135b7565b6000808a8a6040516114ed9291906145a1565b604051908190038120611504918e906020016145b1565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b8981101561180e57600060018489846020811061156d5761156d614252565b61157a91901a601b614508565b8e8e8681811061158c5761158c614252565b905060200201358d8d878181106115a5576115a5614252565b90506020020135604051600081526020016040526040516115e2949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611604573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff8082168552929650929450840191610100900416600281111561168457611684614572565b600281111561169557611695614572565b90525092506001836020015160028111156116b2576116b2614572565b14611719576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610b0d565b8251600090879060ff16601f811061173357611733614252565b602002015173ffffffffffffffffffffffffffffffffffffffff16146117b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610b0d565b8086846000015160ff16601f81106117cf576117cf614252565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117fa600186614508565b9450508061180790614281565b905061154e565b50505061181f833383858e8e612e07565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b1580156118cc57600080fd5b505afa1580156118e0573d6000803e3d6000fd5b5050505066038d7ea4c68000821115611925576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061192f610841565b9050600061197287878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061023c92505050565b905061198085858385612fd5565b98975050505050505050565b6060600c805461199b90614022565b90506000036119d6576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610ea890614022565b855185518560ff16601f831115611a56576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610b0d565b80600003611ac0576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610b0d565b818314611b4e576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610b0d565b611b598160036145c5565b8311611bc1576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610b0d565b611bc961267c565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611c10908861311d565b60055415611dc557600554600090611c2a906001906145dc565b9050600060058281548110611c4157611c41614252565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611c7b57611c7b614252565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611cfb57611cfb6145ef565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611d6457611d646145ef565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611c10915050565b60005b81515181101561222c5760006004600084600001518481518110611dee57611dee614252565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611e3857611e38614572565b14611e9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610b0d565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611ed057611ed0614252565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115611f7157611f71614572565b021790555060009150611f819050565b6004600084602001518481518110611f9b57611f9b614252565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611fe557611fe5614572565b1461204c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610b0d565b6040805180820190915260ff82168152602081016002815250600460008460200151848151811061207f5761207f614252565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561212057612120614572565b02179055505082518051600592508390811061213e5761213e614252565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90931692909217909155820151805160069190839081106121ba576121ba614252565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790558061222481614281565b915050611dc8565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff43811682029290921780855592048116929182916014916122e49184917401000000000000000000000000000000000000000090041661461e565b92506101000a81548163ffffffff021916908363ffffffff1602179055506123434630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a00151613136565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986123fa988b9891977401000000000000000000000000000000000000000090920463ffffffff1696909591949193919261463b565b60405180910390a15050505050505050505050565b604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c0100000000000000000000000080830482166060850152700100000000000000000000000000000000830468ffffffffffffffffff166080850152790100000000000000000000000000000000000000000000000000830464ffffffffff1660a0808601919091527e0100000000000000000000000000000000000000000000000000000000000090930461ffff1660c08501526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08601527c01000000000000000000000000000000000000000000000000000000009004909116610100840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa15801561259d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c191906146eb565b5093505092505080426125d491906145dc565b836020015163ffffffff161080156125f657506000836020015163ffffffff16115b1561262457505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b60008213612661576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610b0d565b5092915050565b61267061267c565b612679816131e1565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146126fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0d565b565b6126fd61267c565b600b546bffffffffffffffffffffffff1660000361272157565b600061272b610de2565b90508051600003612768576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600b54600091612787916bffffffffffffffffffffffff1661473b565b905060005b82518110156128535781600a60008584815181106127ac576127ac614252565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff166128149190614766565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508061284c90614281565b905061278c565b508151612860908261478b565b600b80546000906128809084906bffffffffffffffffffffffff1661422d565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c0100000000000000000000000081048316606083015268ffffffffffffffffff700100000000000000000000000000000000820416608083015264ffffffffff79010000000000000000000000000000000000000000000000000082041660a083015261ffff7e01000000000000000000000000000000000000000000000000000000000000909104811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08501527c0100000000000000000000000000000000000000000000000000000000900490931661010080840191909152850151919291161115612a6d576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854600090700100000000000000000000000000000000900468ffffffffffffffffff1690506000612aaa8560e001513a848860800151612fd5565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612b06576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083610100015163ffffffff1642612b1f91906147b3565b905060003087604001518860a001518960c001516001612b3f91906147c6565b8a5180516020918201206101008d015160e08e0151604051612bf398979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b6040516020818303038152906040528051906020012090506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001846bffffffffffffffffffffffff168152602001886040015173ffffffffffffffffffffffffffffffffffffffff1681526020018860a0015167ffffffffffffffff1681526020018860e0015163ffffffff168152602001886080015168ffffffffffffffffff1681526020018568ffffffffffffffffff168152602001866040015163ffffffff1664ffffffffff168152602001866060015163ffffffff1664ffffffffff1681526020018363ffffffff16815250955085604051602001612d029190613c24565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009384526007909252909120555092949350505050565b6000612d5d8260206145c5565b612d688560206145c5565b612d74886101446147b3565b612d7e91906147b3565b612d8891906147b3565b612d939060006147b3565b9050368114612dfe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610b0d565b50505050505050565b606080808080612e19868801886148c2565b8451949950929750909550935091501580612e3657508351855114155b80612e4357508251855114155b80612e5057508151855114155b80612e5d57508051855114155b15612e94576040517f0be3632800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8551811015612fc7576000612f2c878381518110612eb757612eb7614252565b6020026020010151878481518110612ed157612ed1614252565b6020026020010151878581518110612eeb57612eeb614252565b6020026020010151878681518110612f0557612f05614252565b6020026020010151878781518110612f1f57612f1f614252565b60200260200101516132d6565b90506000816006811115612f4257612f42614572565b1480612f5f57506001816006811115612f5d57612f5d614572565b145b15612fb657868281518110612f7657612f76614252565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b50612fc081614281565b9050612e97565b505050505050505050505050565b6008546000908190869061300d9063ffffffff6c0100000000000000000000000082048116916801000000000000000090041661461e565b613017919061461e565b60085463ffffffff919091169150790100000000000000000000000000000000000000000000000000900464ffffffffff1685101561307a57600854790100000000000000000000000000000000000000000000000000900464ffffffffff1694505b600854600090612710906130949063ffffffff16886145c5565b61309e9190614994565b6130a890876147b3565b905060006130b5826134e6565b905060006130d1846bffffffffffffffffffffffff84166145c5565b905060006130ed68ffffffffffffffffff808916908a16614766565b905061310f61310a6bffffffffffffffffffffffff8316846147b3565b613515565b9a9950505050505050505050565b6000613127610de2565b511115610d8e57610d8e612707565b6000808a8a8a8a8a8a8a8a8a60405160200161315a999897969594939291906149a8565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613260576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080838060200190518101906132ed9190614a74565b905060006132fa3a6134e6565b905060008261012001518361010001516133149190614b3c565b6133259064ffffffffff168361478b565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298b8b878960e0015168ffffffffffffffffff16886133849190614766565b338b6040518763ffffffff1660e01b81526004016133a796959493929190614b5a565b60408051808303816000875af11580156133c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133e99190614bd6565b9092509050600082600681111561340257613402614572565b148061341f5750600182600681111561341d5761341d614572565b145b156134d85760008b81526007602052604081205561343d8184614766565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0870151600b805468ffffffffffffffffff909216939092916134a991859116614766565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b509998505050505050505050565b600061350f6134f361240f565b61350584670de0b6b3a76400006145c5565b61310a9190614994565b92915050565b60006bffffffffffffffffffffffff8211156135b3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b0d565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f8401126135e857600080fd5b50813567ffffffffffffffff81111561360057600080fd5b60208301915083602082850101111561361857600080fd5b9250929050565b6000806020838503121561363257600080fd5b823567ffffffffffffffff81111561364957600080fd5b613655858286016135d6565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156136b4576136b4613661565b60405290565b604051610160810167ffffffffffffffff811182821017156136b4576136b4613661565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561372557613725613661565b604052919050565b63ffffffff8116811461267957600080fd5b80356111708161372d565b68ffffffffffffffffff8116811461267957600080fd5b80356111708161374a565b64ffffffffff8116811461267957600080fd5b80356111708161376c565b803561ffff8116811461117057600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461117057600080fd5b600061012082840312156137db57600080fd5b6137e3613690565b6137ec8361373f565b81526137fa6020840161373f565b602082015261380b6040840161373f565b604082015261381c6060840161373f565b606082015261382d60808401613761565b608082015261383e60a0840161377f565b60a082015261384f60c0840161378a565b60c082015261386060e0840161379c565b60e082015261010061387381850161373f565b908201529392505050565b6000815180845260005b818110156138a457602081850181015186830182015201613888565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006138f5602083018461387e565b9392505050565b600082601f83011261390d57600080fd5b813567ffffffffffffffff81111561392757613927613661565b61395860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016136de565b81815284602083860101111561396d57600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561399c57600080fd5b813567ffffffffffffffff8111156139b357600080fd5b6139bf848285016138fc565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461267957600080fd5b8035611170816139c7565b6bffffffffffffffffffffffff8116811461267957600080fd5b8035611170816139f4565b60008060408385031215613a2c57600080fd5b8235613a37816139c7565b91506020830135613a47816139f4565b809150509250929050565b600081518084526020808501945080840160005b83811015613a9857815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613a66565b509495945050505050565b6020815260006138f56020830184613a52565b600060208284031215613ac857600080fd5b5035919050565b600060208284031215613ae157600080fd5b813567ffffffffffffffff811115613af857600080fd5b820161016081850312156138f557600080fd5b805182526020810151613b36602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613b5660408401826bffffffffffffffffffffffff169052565b506060810151613b7e606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613b9a608084018267ffffffffffffffff169052565b5060a0810151613bb260a084018263ffffffff169052565b5060c0810151613bcf60c084018268ffffffffffffffffff169052565b5060e0810151613bec60e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b610160810161350f8284613b0b565b60008083601f840112613c4557600080fd5b50813567ffffffffffffffff811115613c5d57600080fd5b6020830191508360208260051b850101111561361857600080fd5b60008060008060008060008060e0898b031215613c9457600080fd5b606089018a811115613ca557600080fd5b8998503567ffffffffffffffff80821115613cbf57600080fd5b613ccb8c838d016135d6565b909950975060808b0135915080821115613ce457600080fd5b613cf08c838d01613c33565b909750955060a08b0135915080821115613d0957600080fd5b50613d168b828c01613c33565b999c989b50969995989497949560c00135949350505050565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151613d83608084018268ffffffffffffffffff169052565b5060a0830151613d9c60a084018264ffffffffff169052565b5060c0830151613db260c084018261ffff169052565b5060e0830151613de260e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b506101008381015163ffffffff8116848301525b505092915050565b67ffffffffffffffff8116811461267957600080fd5b803561117081613dfe565b600080600080600060808688031215613e3757600080fd5b8535613e4281613dfe565b9450602086013567ffffffffffffffff811115613e5e57600080fd5b613e6a888289016135d6565b9095509350506040860135613e7e8161372d565b949793965091946060013592915050565b600067ffffffffffffffff821115613ea957613ea9613661565b5060051b60200190565b600082601f830112613ec457600080fd5b81356020613ed9613ed483613e8f565b6136de565b82815260059290921b84018101918181019086841115613ef857600080fd5b8286015b84811015613f1c578035613f0f816139c7565b8352918301918301613efc565b509695505050505050565b803560ff8116811461117057600080fd5b60008060008060008060c08789031215613f5157600080fd5b863567ffffffffffffffff80821115613f6957600080fd5b613f758a838b01613eb3565b97506020890135915080821115613f8b57600080fd5b613f978a838b01613eb3565b9650613fa560408a01613f27565b95506060890135915080821115613fbb57600080fd5b613fc78a838b016138fc565b9450613fd560808a01613e14565b935060a0890135915080821115613feb57600080fd5b50613ff889828a016138fc565b9150509295509295509295565b60006020828403121561401757600080fd5b81356138f5816139c7565b600181811c9082168061403657607f821691505b60208210810361406f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105ec57600081815260208120601f850160051c8101602086101561409c5750805b601f850160051c820191505b81811015610a88578281556001016140a8565b67ffffffffffffffff8311156140d3576140d3613661565b6140e7836140e18354614022565b83614075565b6000601f84116001811461413957600085156141035750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b1783556141cf565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156141885786850135825560209485019460019092019101614168565b50868210156141c3577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b80516111708161374a565b6000602082840312156141f357600080fd5b81516138f58161374a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff828116828216039080821115612661576126616141fe565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036142b2576142b26141fe565b5060010190565b600061016082360312156142cc57600080fd5b6142d46136ba565b823567ffffffffffffffff8111156142eb57600080fd5b6142f7368286016138fc565b82525060208301356020820152614310604084016139e9565b604082015261432160608401613a0e565b606082015261433260808401613761565b608082015261434360a08401613e14565b60a082015261435460c08401613e14565b60c082015261436560e0840161373f565b60e082015261010061437881850161378a565b9082015261012061438a848201613e14565b9082015261014061439c8482016139e9565b9082015292915050565b6000602082840312156143b857600080fd5b81356138f581613dfe565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126143f857600080fd5b83018035915067ffffffffffffffff82111561441357600080fd5b60200191503681900382131561361857600080fd5b60006020828403121561443a57600080fd5b6138f58261378a565b60006020828403121561445557600080fd5b81356138f58161372d565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061310f60e0830184613b0b565b60ff818116838216019081111561350f5761350f6141fe565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061456357614563614521565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b808202811582820484141761350f5761350f6141fe565b8181038181111561350f5761350f6141fe565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff818116838216019080821115612661576126616141fe565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261466b8184018a613a52565b9050828103608084015261467f8189613a52565b905060ff871660a084015282810360c084015261469c818761387e565b905067ffffffffffffffff851660e08401528281036101008401526146c1818561387e565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461117057600080fd5b600080600080600060a0868803121561470357600080fd5b61470c866146d1565b945060208601519350604086015192506060860151915061472f608087016146d1565b90509295509295909350565b60006bffffffffffffffffffffffff8084168061475a5761475a614521565b92169190910492915050565b6bffffffffffffffffffffffff818116838216019080821115612661576126616141fe565b6bffffffffffffffffffffffff818116838216028082169190828114613df657613df66141fe565b8082018082111561350f5761350f6141fe565b67ffffffffffffffff818116838216019080821115612661576126616141fe565b600082601f8301126147f857600080fd5b81356020614808613ed483613e8f565b82815260059290921b8401810191818101908684111561482757600080fd5b8286015b84811015613f1c578035835291830191830161482b565b600082601f83011261485357600080fd5b81356020614863613ed483613e8f565b82815260059290921b8401810191818101908684111561488257600080fd5b8286015b84811015613f1c57803567ffffffffffffffff8111156148a65760008081fd5b6148b48986838b01016138fc565b845250918301918301614886565b600080600080600060a086880312156148da57600080fd5b853567ffffffffffffffff808211156148f257600080fd5b6148fe89838a016147e7565b9650602088013591508082111561491457600080fd5b61492089838a01614842565b9550604088013591508082111561493657600080fd5b61494289838a01614842565b9450606088013591508082111561495857600080fd5b61496489838a01614842565b9350608088013591508082111561497a57600080fd5b5061498788828901614842565b9150509295509295909350565b6000826149a3576149a3614521565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b1660408501528160608501526149ef8285018b613a52565b91508382036080850152614a03828a613a52565b915060ff881660a085015283820360c0850152614a20828861387e565b90861660e085015283810361010085015290506146c1818561387e565b8051611170816139c7565b8051611170816139f4565b805161117081613dfe565b80516111708161372d565b80516111708161376c565b60006101608284031215614a8757600080fd5b614a8f6136ba565b82518152614a9f60208401614a3d565b6020820152614ab060408401614a48565b6040820152614ac160608401614a3d565b6060820152614ad260808401614a53565b6080820152614ae360a08401614a5e565b60a0820152614af460c084016141d6565b60c0820152614b0560e084016141d6565b60e0820152610100614b18818501614a69565b90820152610120614b2a848201614a69565b90820152610140613873848201614a5e565b64ffffffffff818116838216019080821115612661576126616141fe565b6000610200808352614b6e8184018a61387e565b90508281036020840152614b82818961387e565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614bcb905060a0830184613b0b565b979650505050505050565b60008060408385031215614be957600080fd5b825160078110614bf857600080fd5b6020840151909250613a47816139f456fea164736f6c6343000813000a", + Bin: "0x60c06040523480156200001157600080fd5b506040516200556438038062005564833981016040819052620000349162000474565b8282828260013380600081620000915760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c457620000c48162000140565b50505015156080526001600160a01b038116620000f457604051632530e88560e11b815260040160405180910390fd5b6001600160a01b0390811660a052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200013482620001eb565b50505050505062000633565b336001600160a01b038216036200019a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000088565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001f562000349565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160f01b026001600160f01b0364ffffffffff909216600160c81b0264ffffffffff60c81b196001600160481b03909416600160801b0293909316600160801b600160f01b031963ffffffff9586166c010000000000000000000000000263ffffffff60601b19978716680100000000000000000297909716600160401b600160801b0319998716640100000000026001600160401b0319909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e0830151610100840151909216600160e01b026001600160e01b0390921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906200033e9083906200057d565b60405180910390a150565b6200035362000355565b565b6000546001600160a01b03163314620003535760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000088565b80516001600160a01b0381168114620003c957600080fd5b919050565b60405161012081016001600160401b03811182821017156200040057634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff81168114620003c957600080fd5b80516001600160481b0381168114620003c957600080fd5b805164ffffffffff81168114620003c957600080fd5b805161ffff81168114620003c957600080fd5b80516001600160e01b0381168114620003c957600080fd5b60008060008385036101608112156200048c57600080fd5b6200049785620003b1565b935061012080601f1983011215620004ae57600080fd5b620004b8620003ce565b9150620004c86020870162000406565b8252620004d86040870162000406565b6020830152620004eb6060870162000406565b6040830152620004fe6080870162000406565b60608301526200051160a087016200041b565b60808301526200052460c0870162000433565b60a08301526200053760e0870162000449565b60c08301526101006200054c8188016200045c565b60e08401526200055e82880162000406565b90830152509150620005746101408501620003b1565b90509250925092565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151620005d060808401826001600160481b03169052565b5060a0830151620005ea60a084018264ffffffffff169052565b5060c08301516200060160c084018261ffff169052565b5060e08301516200061d60e08401826001600160e01b03169052565b506101009283015163ffffffff16919092015290565b60805160a051614ee16200068360003960008181610845015281816109d301528181610ca601528181610f3a015281816110450152818161183001526133aa0152600061126e0152614ee16000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806381ff7048116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610560578063e4ddcea614610573578063f2fde38b1461058957600080fd5b8063c3f909d4146103b0578063d227d24514610528578063d328a91e1461055857600080fd5b8063a631571e116100bd578063a631571e1461035d578063afcb95d71461037d578063b1dc65a41461039d57600080fd5b806381ff7048146102b557806385b214cf146103225780638da5cb5b1461033557600080fd5b806366316d8d116101455780637f15e1661161011f5780637f15e16614610285578063814118341461029857806381f1b938146102ad57600080fd5b806366316d8d1461026257806379ba5097146102755780637d4807871461027d57600080fd5b8063181f5a7711610176578063181f5a77146101ba5780632a905ccc1461020c57806359b5b7ac1461022e57600080fd5b8063083a5466146101925780631112dadc146101a7575b600080fd5b6101a56101a0366004613857565b61059c565b005b6101a56101b5366004613a00565b6105f1565b6101f66040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e312e300000000081525081565b6040516102039190613b24565b60405180910390f35b610214610841565b60405168ffffffffffffffffff9091168152602001610203565b61021461023c366004613bc5565b50600854700100000000000000000000000000000000900468ffffffffffffffffff1690565b6101a5610270366004613c54565b6108d7565b6101a5610a90565b6101a5610b92565b6101a5610293366004613857565b610d92565b6102a0610de2565b6040516102039190613cde565b6101f6610e51565b6102ff60015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610203565b6101a5610330366004613cf1565b610f22565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610203565b61037061036b366004613d0a565b610fd4565b6040516102039190613e5f565b604080516001815260006020820181905291810191909152606001610203565b6101a56103ab366004613eb3565b611175565b61051b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810468ffffffffffffffffff166080830152790100000000000000000000000000000000000000000000000000810464ffffffffff1660a08301527e01000000000000000000000000000000000000000000000000000000000000900461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08301527c0100000000000000000000000000000000000000000000000000000000900490911661010082015290565b6040516102039190613f6a565b61053b61053636600461405a565b61182c565b6040516bffffffffffffffffffffffff9091168152602001610203565b6101f661198c565b6101a561056e366004614173565b6119e3565b61057b61240f565b604051908152602001610203565b6101a5610597366004614240565b612668565b6105a461267c565b60008190036105df576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105ec8284836142f6565b505050565b6105f96126ff565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff64ffffffffff909216790100000000000000000000000000000000000000000000000000027fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90941670010000000000000000000000000000000002939093167fffff0000000000000000000000000000ffffffffffffffffffffffffffffffff63ffffffff9586166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9787166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e08301516101008401519092167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f518486290610836908390613f6a565b60405180910390a150565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d2919061441c565b905090565b6108df612707565b806bffffffffffffffffffffffff166000036109195750336000908152600a60205260409020546bffffffffffffffffffffffff16610973565b336000908152600a60205260409020546bffffffffffffffffffffffff80831691161015610973576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906109a09084906bffffffffffffffffffffffff16614468565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506109f57f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b158015610a7457600080fd5b505af1158015610a88573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b9a6126ff565b610ba2612707565b6000610bac610de2565b905060005b8151811015610d8e576000600a6000848481518110610bd257610bd261448d565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d7d576000600a6000858581518110610c3157610c3161448d565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610cc87f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610cf557610cf561448d565b6020026020010151836040518363ffffffff1660e01b8152600401610d4a92919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d6457600080fd5b505af1158015610d78573d6000803e3d6000fd5b505050505b50610d87816144bc565b9050610bb1565b5050565b610d9a61267c565b6000819003610dd5576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105ec8284836142f6565b60606006805480602002602001604051908101604052809291908181526020018280548015610e4757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e1c575b5050505050905090565b6060600d8054610e609061425d565b9050600003610e9b576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610ea89061425d565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed49061425d565b8015610e475780601f10610ef657610100808354040283529160200191610e47565b820191906000526020600020905b815481529060010190602001808311610f0457509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f91576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f416906108369083815260200190565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461109c576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110ad6110a8836144f4565b6128b2565b90506110bf6060830160408401614240565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff3261110d60c0870160a088016145e1565b61111f61016088016101408901614240565b61112988806145fe565b61113b6101208b016101008c01614663565b60208b01356111516101008d0160e08e0161467e565b8b6040516111679998979695949392919061469b565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16040805160608101825260025480825260035460ff8082166020850152610100909104169282019290925290831461125c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f6e666967446967657374206d69736d6174636800000000000000000000006044820152606401610b0d565b61126a8b8b8b8b8b8b612d50565b60007f0000000000000000000000000000000000000000000000000000000000000000156112c7576002826020015183604001516112a89190614743565b6112b2919061478b565b6112bd906001614743565b60ff1690506112dd565b60208201516112d7906001614743565b60ff1690505b888114611346576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610b0d565b8887146113af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f7369676e617475726573206f7574206f6620726567697374726174696f6e00006044820152606401610b0d565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113f2576113f26147ad565b6002811115611403576114036147ad565b9052509050600281602001516002811115611420576114206147ad565b14801561146757506006816000015160ff16815481106114425761144261448d565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b6114cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610b0d565b50505050506114da6137ef565b6000808a8a6040516114ed9291906147dc565b604051908190038120611504918e906020016147ec565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b8981101561180e57600060018489846020811061156d5761156d61448d565b61157a91901a601b614743565b8e8e8681811061158c5761158c61448d565b905060200201358d8d878181106115a5576115a561448d565b90506020020135604051600081526020016040526040516115e2949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611604573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff80821685529296509294508401916101009004166002811115611684576116846147ad565b6002811115611695576116956147ad565b90525092506001836020015160028111156116b2576116b26147ad565b14611719576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610b0d565b8251600090879060ff16601f81106117335761173361448d565b602002015173ffffffffffffffffffffffffffffffffffffffff16146117b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610b0d565b8086846000015160ff16601f81106117cf576117cf61448d565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117fa600186614743565b94505080611807906144bc565b905061154e565b50505061181f833383858e8e612e07565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b1580156118cc57600080fd5b505afa1580156118e0573d6000803e3d6000fd5b5050505066038d7ea4c68000821115611925576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061192f610841565b9050600061197287878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061023c92505050565b905061198085858385612fd7565b98975050505050505050565b6060600c805461199b9061425d565b90506000036119d6576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610ea89061425d565b855185518560ff16601f831115611a56576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610b0d565b80600003611ac0576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610b0d565b818314611b4e576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610b0d565b611b59816003614800565b8311611bc1576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610b0d565b611bc961267c565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611c109088613144565b60055415611dc557600554600090611c2a90600190614817565b9050600060058281548110611c4157611c4161448d565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611c7b57611c7b61448d565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611cfb57611cfb61482a565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611d6457611d6461482a565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611c10915050565b60005b81515181101561222c5760006004600084600001518481518110611dee57611dee61448d565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611e3857611e386147ad565b14611e9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610b0d565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611ed057611ed061448d565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115611f7157611f716147ad565b021790555060009150611f819050565b6004600084602001518481518110611f9b57611f9b61448d565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611fe557611fe56147ad565b1461204c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610b0d565b6040805180820190915260ff82168152602081016002815250600460008460200151848151811061207f5761207f61448d565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115612120576121206147ad565b02179055505082518051600592508390811061213e5761213e61448d565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90931692909217909155820151805160069190839081106121ba576121ba61448d565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905580612224816144bc565b915050611dc8565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff43811682029290921780855592048116929182916014916122e491849174010000000000000000000000000000000000000000900416614859565b92506101000a81548163ffffffff021916908363ffffffff1602179055506123434630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a0015161315d565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986123fa988b9891977401000000000000000000000000000000000000000090920463ffffffff16969095919491939192614876565b60405180910390a15050505050505050505050565b604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c0100000000000000000000000080830482166060850152700100000000000000000000000000000000830468ffffffffffffffffff166080850152790100000000000000000000000000000000000000000000000000830464ffffffffff1660a0808601919091527e0100000000000000000000000000000000000000000000000000000000000090930461ffff1660c08501526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08601527c01000000000000000000000000000000000000000000000000000000009004909116610100840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa15801561259d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c19190614926565b5093505092505080426125d49190614817565b836020015163ffffffff161080156125f657506000836020015163ffffffff16115b1561262457505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b60008213612661576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610b0d565b5092915050565b61267061267c565b61267981613208565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146126fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0d565b565b6126fd61267c565b600b546bffffffffffffffffffffffff1660000361272157565b600061272b610de2565b90508051600003612768576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600b54600091612787916bffffffffffffffffffffffff16614976565b905060005b82518110156128535781600a60008584815181106127ac576127ac61448d565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff1661281491906149a1565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508061284c906144bc565b905061278c565b50815161286090826149c6565b600b80546000906128809084906bffffffffffffffffffffffff16614468565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c0100000000000000000000000081048316606083015268ffffffffffffffffff700100000000000000000000000000000000820416608083015264ffffffffff79010000000000000000000000000000000000000000000000000082041660a083015261ffff7e01000000000000000000000000000000000000000000000000000000000000909104811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08501527c0100000000000000000000000000000000000000000000000000000000900490931661010080840191909152850151919291161115612a6d576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854600090700100000000000000000000000000000000900468ffffffffffffffffff1690506000612aaa8560e001513a848860800151612fd7565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612b06576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083610100015163ffffffff1642612b1f91906149ee565b905060003087604001518860a001518960c001516001612b3f9190614a01565b8a5180516020918201206101008d015160e08e0151604051612bf398979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b6040516020818303038152906040528051906020012090506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001846bffffffffffffffffffffffff168152602001886040015173ffffffffffffffffffffffffffffffffffffffff1681526020018860a0015167ffffffffffffffff1681526020018860e0015163ffffffff168152602001886080015168ffffffffffffffffff1681526020018568ffffffffffffffffff168152602001866040015163ffffffff1664ffffffffff168152602001866060015163ffffffff1664ffffffffff1681526020018363ffffffff16815250955085604051602001612d029190613e5f565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009384526007909252909120555092949350505050565b6000612d5d826020614800565b612d68856020614800565b612d74886101446149ee565b612d7e91906149ee565b612d8891906149ee565b612d939060006149ee565b9050368114612dfe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610b0d565b50505050505050565b606080808080612e1986880188614afd565b8451949950929750909550935091501580612e3657508351855114155b80612e4357508251855114155b80612e5057508151855114155b80612e5d57508051855114155b15612e94576040517f0be3632800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8551811015612fc9576000612f2e878381518110612eb757612eb761448d565b6020026020010151878481518110612ed157612ed161448d565b6020026020010151878581518110612eeb57612eeb61448d565b6020026020010151878681518110612f0557612f0561448d565b6020026020010151878781518110612f1f57612f1f61448d565b60200260200101518c516132fd565b90506000816006811115612f4457612f446147ad565b1480612f6157506001816006811115612f5f57612f5f6147ad565b145b15612fb857868281518110612f7857612f7861448d565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b50612fc2816144bc565b9050612e97565b505050505050505050505050565b600854600090790100000000000000000000000000000000000000000000000000900464ffffffffff1684101561303257600854790100000000000000000000000000000000000000000000000000900464ffffffffff1693505b6008546000906127109061304c9063ffffffff1687614800565b6130569190614bcf565b61306090866149ee565b60085490915060009087906130999063ffffffff6c01000000000000000000000000820481169168010000000000000000900416614859565b6130a39190614859565b63ffffffff16905060006130ed6000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061356d92505050565b9050600061310e826130ff8587614800565b61310991906149ee565b6136af565b9050600061312a68ffffffffffffffffff808916908a166149a1565b905061313681836149a1565b9a9950505050505050505050565b600061314e610de2565b511115610d8e57610d8e612707565b6000808a8a8a8a8a8a8a8a8a60405160200161318199989796959493929190614be3565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613287576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080848060200190518101906133149190614caf565b905060003a82610120015183610100015161332f9190614d77565b64ffffffffff166133409190614800565b905060008460ff166133886000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061356d92505050565b6133929190614bcf565b905060006133a361310983856149ee565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298d8d6133ef3a6136af565b60e08b01516134099068ffffffffffffffffff16896149a1565b338c6040518763ffffffff1660e01b815260040161342c96959493929190614d95565b60408051808303816000875af115801561344a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061346e9190614e11565b90925090506000826006811115613487576134876147ad565b14806134a4575060018260068111156134a2576134a26147ad565b145b1561355d5760008d8152600760205260408120556134c281846149a1565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0880151600b805468ffffffffffffffffff9092169390929161352e918591166149a1565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b509b9a5050505050505050505050565b600046613579816136e3565b156135f557606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156135ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ee9190614e44565b9392505050565b6135fe81613706565b156136a65773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e84604051806080016040528060488152602001614e8d6048913960405160200161365e929190614e5d565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016136899190613b24565b602060405180830381865afa1580156135ca573d6000803e3d6000fd5b50600092915050565b60006136dd6136bc61240f565b6136ce84670de0b6b3a7640000614800565b6136d89190614bcf565b61374d565b92915050565b600061a4b18214806136f7575062066eed82145b806136dd57505062066eee1490565b6000600a82148061371857506101a482145b80613725575062aa37dc82145b80613731575061210582145b8061373e575062014a3382145b806136dd57505062014a341490565b60006bffffffffffffffffffffffff8211156137eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b0d565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f84011261382057600080fd5b50813567ffffffffffffffff81111561383857600080fd5b60208301915083602082850101111561385057600080fd5b9250929050565b6000806020838503121561386a57600080fd5b823567ffffffffffffffff81111561388157600080fd5b61388d8582860161380e565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156138ec576138ec613899565b60405290565b604051610160810167ffffffffffffffff811182821017156138ec576138ec613899565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561395d5761395d613899565b604052919050565b63ffffffff8116811461267957600080fd5b803561117081613965565b68ffffffffffffffffff8116811461267957600080fd5b803561117081613982565b64ffffffffff8116811461267957600080fd5b8035611170816139a4565b803561ffff8116811461117057600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461117057600080fd5b60006101208284031215613a1357600080fd5b613a1b6138c8565b613a2483613977565b8152613a3260208401613977565b6020820152613a4360408401613977565b6040820152613a5460608401613977565b6060820152613a6560808401613999565b6080820152613a7660a084016139b7565b60a0820152613a8760c084016139c2565b60c0820152613a9860e084016139d4565b60e0820152610100613aab818501613977565b908201529392505050565b60005b83811015613ad1578181015183820152602001613ab9565b50506000910152565b60008151808452613af2816020860160208601613ab6565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006135ee6020830184613ada565b600082601f830112613b4857600080fd5b813567ffffffffffffffff811115613b6257613b62613899565b613b9360207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613916565b818152846020838601011115613ba857600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215613bd757600080fd5b813567ffffffffffffffff811115613bee57600080fd5b613bfa84828501613b37565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461267957600080fd5b803561117081613c02565b6bffffffffffffffffffffffff8116811461267957600080fd5b803561117081613c2f565b60008060408385031215613c6757600080fd5b8235613c7281613c02565b91506020830135613c8281613c2f565b809150509250929050565b600081518084526020808501945080840160005b83811015613cd357815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613ca1565b509495945050505050565b6020815260006135ee6020830184613c8d565b600060208284031215613d0357600080fd5b5035919050565b600060208284031215613d1c57600080fd5b813567ffffffffffffffff811115613d3357600080fd5b820161016081850312156135ee57600080fd5b805182526020810151613d71602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613d9160408401826bffffffffffffffffffffffff169052565b506060810151613db9606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613dd5608084018267ffffffffffffffff169052565b5060a0810151613ded60a084018263ffffffff169052565b5060c0810151613e0a60c084018268ffffffffffffffffff169052565b5060e0810151613e2760e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b61016081016136dd8284613d46565b60008083601f840112613e8057600080fd5b50813567ffffffffffffffff811115613e9857600080fd5b6020830191508360208260051b850101111561385057600080fd5b60008060008060008060008060e0898b031215613ecf57600080fd5b606089018a811115613ee057600080fd5b8998503567ffffffffffffffff80821115613efa57600080fd5b613f068c838d0161380e565b909950975060808b0135915080821115613f1f57600080fd5b613f2b8c838d01613e6e565b909750955060a08b0135915080821115613f4457600080fd5b50613f518b828c01613e6e565b999c989b50969995989497949560c00135949350505050565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151613fbe608084018268ffffffffffffffffff169052565b5060a0830151613fd760a084018264ffffffffff169052565b5060c0830151613fed60c084018261ffff169052565b5060e083015161401d60e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b506101008381015163ffffffff8116848301525b505092915050565b67ffffffffffffffff8116811461267957600080fd5b803561117081614039565b60008060008060006080868803121561407257600080fd5b853561407d81614039565b9450602086013567ffffffffffffffff81111561409957600080fd5b6140a58882890161380e565b90955093505060408601356140b981613965565b949793965091946060013592915050565b600067ffffffffffffffff8211156140e4576140e4613899565b5060051b60200190565b600082601f8301126140ff57600080fd5b8135602061411461410f836140ca565b613916565b82815260059290921b8401810191818101908684111561413357600080fd5b8286015b8481101561415757803561414a81613c02565b8352918301918301614137565b509695505050505050565b803560ff8116811461117057600080fd5b60008060008060008060c0878903121561418c57600080fd5b863567ffffffffffffffff808211156141a457600080fd5b6141b08a838b016140ee565b975060208901359150808211156141c657600080fd5b6141d28a838b016140ee565b96506141e060408a01614162565b955060608901359150808211156141f657600080fd5b6142028a838b01613b37565b945061421060808a0161404f565b935060a089013591508082111561422657600080fd5b5061423389828a01613b37565b9150509295509295509295565b60006020828403121561425257600080fd5b81356135ee81613c02565b600181811c9082168061427157607f821691505b6020821081036142aa577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105ec57600081815260208120601f850160051c810160208610156142d75750805b601f850160051c820191505b81811015610a88578281556001016142e3565b67ffffffffffffffff83111561430e5761430e613899565b6143228361431c835461425d565b836142b0565b6000601f841160018114614374576000851561433e5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b17835561440a565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156143c357868501358255602094850194600190920191016143a3565b50868210156143fe577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b805161117081613982565b60006020828403121561442e57600080fd5b81516135ee81613982565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff82811682821603908082111561266157612661614439565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036144ed576144ed614439565b5060010190565b6000610160823603121561450757600080fd5b61450f6138f2565b823567ffffffffffffffff81111561452657600080fd5b61453236828601613b37565b8252506020830135602082015261454b60408401613c24565b604082015261455c60608401613c49565b606082015261456d60808401613999565b608082015261457e60a0840161404f565b60a082015261458f60c0840161404f565b60c08201526145a060e08401613977565b60e08201526101006145b38185016139c2565b908201526101206145c584820161404f565b908201526101406145d7848201613c24565b9082015292915050565b6000602082840312156145f357600080fd5b81356135ee81614039565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261463357600080fd5b83018035915067ffffffffffffffff82111561464e57600080fd5b60200191503681900382131561385057600080fd5b60006020828403121561467557600080fd5b6135ee826139c2565b60006020828403121561469057600080fd5b81356135ee81613965565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061313660e0830184613d46565b60ff81811683821601908111156136dd576136dd614439565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061479e5761479e61475c565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b80820281158282048414176136dd576136dd614439565b818103818111156136dd576136dd614439565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff81811683821601908082111561266157612661614439565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526148a68184018a613c8d565b905082810360808401526148ba8189613c8d565b905060ff871660a084015282810360c08401526148d78187613ada565b905067ffffffffffffffff851660e08401528281036101008401526148fc8185613ada565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461117057600080fd5b600080600080600060a0868803121561493e57600080fd5b6149478661490c565b945060208601519350604086015192506060860151915061496a6080870161490c565b90509295509295909350565b60006bffffffffffffffffffffffff808416806149955761499561475c565b92169190910492915050565b6bffffffffffffffffffffffff81811683821601908082111561266157612661614439565b6bffffffffffffffffffffffff81811683821602808216919082811461403157614031614439565b808201808211156136dd576136dd614439565b67ffffffffffffffff81811683821601908082111561266157612661614439565b600082601f830112614a3357600080fd5b81356020614a4361410f836140ca565b82815260059290921b84018101918181019086841115614a6257600080fd5b8286015b848110156141575780358352918301918301614a66565b600082601f830112614a8e57600080fd5b81356020614a9e61410f836140ca565b82815260059290921b84018101918181019086841115614abd57600080fd5b8286015b8481101561415757803567ffffffffffffffff811115614ae15760008081fd5b614aef8986838b0101613b37565b845250918301918301614ac1565b600080600080600060a08688031215614b1557600080fd5b853567ffffffffffffffff80821115614b2d57600080fd5b614b3989838a01614a22565b96506020880135915080821115614b4f57600080fd5b614b5b89838a01614a7d565b95506040880135915080821115614b7157600080fd5b614b7d89838a01614a7d565b94506060880135915080821115614b9357600080fd5b614b9f89838a01614a7d565b93506080880135915080821115614bb557600080fd5b50614bc288828901614a7d565b9150509295509295909350565b600082614bde57614bde61475c565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614c2a8285018b613c8d565b91508382036080850152614c3e828a613c8d565b915060ff881660a085015283820360c0850152614c5b8288613ada565b90861660e085015283810361010085015290506148fc8185613ada565b805161117081613c02565b805161117081613c2f565b805161117081614039565b805161117081613965565b8051611170816139a4565b60006101608284031215614cc257600080fd5b614cca6138f2565b82518152614cda60208401614c78565b6020820152614ceb60408401614c83565b6040820152614cfc60608401614c78565b6060820152614d0d60808401614c8e565b6080820152614d1e60a08401614c99565b60a0820152614d2f60c08401614411565b60c0820152614d4060e08401614411565b60e0820152610100614d53818501614ca4565b90820152610120614d65848201614ca4565b90820152610140613aab848201614c99565b64ffffffffff81811683821601908082111561266157612661614439565b6000610200808352614da98184018a613ada565b90508281036020840152614dbd8189613ada565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614e06905060a0830184613d46565b979650505050505050565b60008060408385031215614e2457600080fd5b825160078110614e3357600080fd5b6020840151909250613c8281613c2f565b600060208284031215614e5657600080fd5b5051919050565b60008351614e6f818460208801613ab6565b835190830190614e83818360208801613ab6565b0194935050505056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", } var FunctionsCoordinatorABI = FunctionsCoordinatorMetaData.ABI diff --git a/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt index cff49cd07c2..3543116d21d 100644 --- a/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -4,7 +4,7 @@ functions_allow_list: ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServ functions_billing_registry_events_mock: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistryEventsMock.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistryEventsMock.bin 50deeb883bd9c3729702be335c0388f9d8553bab4be5e26ecacac496a89e2b77 functions_client: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClient.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClient.bin 2368f537a04489c720a46733f8596c4fc88a31062ecfa966d05f25dd98608aca functions_client_example: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClientExample.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClientExample.bin abf32e69f268f40e8530eb8d8e96bf310b798a4c0049a58022d9d2fb527b601b -functions_coordinator: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.bin 9e11effc1922d258d3fc38564b87f4466c56162f33d553ec6d66edcfa55923af +functions_coordinator: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.bin 948c04942910f308942fdde460317f9ec038b6b702b018471ce6157a14a09072 functions_load_test_client: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsLoadTestClient.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsLoadTestClient.bin c8dbbd5ebb34435800d6674700068837c3a252db60046a14b0e61e829db517de functions_oracle_events_mock: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracleEventsMock.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracleEventsMock.bin 3ca70f966f8fe751987f0ccb50bebb6aa5be77e4a9f835d1ae99e0e9bfb7d52c functions_router: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.bin 9dedd3a36043605fd9bedf821e7ec5b4281a5c7ae2e4a1955f37aff8ba13519f From b811f0093a787754ad836049e58cc8cefec67d91 Mon Sep 17 00:00:00 2001 From: Cedric Date: Thu, 9 Nov 2023 17:43:09 +0000 Subject: [PATCH 3/7] [fix] Use correct format for GH run URL (#11246) --- tools/flakeytests/utils.go | 2 +- tools/flakeytests/utils_test.go | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/flakeytests/utils.go b/tools/flakeytests/utils.go index 698a9b49c95..d2326c47262 100644 --- a/tools/flakeytests/utils.go +++ b/tools/flakeytests/utils.go @@ -42,7 +42,7 @@ func getGithubMetadata(repo string, eventName string, sha string, e io.Reader, r log.Fatalf("Error unmarshaling gh event at path") } - runURL := fmt.Sprintf("%s/actions/%s", repo, runID) + runURL := fmt.Sprintf("github.com/%s/actions/runs/%s", repo, runID) basicCtx := &Context{Repository: repo, CommitSHA: sha, Type: eventName, RunURL: runURL} switch eventName { case "pull_request": diff --git a/tools/flakeytests/utils_test.go b/tools/flakeytests/utils_test.go index 761d9cd255c..6ea912d11d4 100644 --- a/tools/flakeytests/utils_test.go +++ b/tools/flakeytests/utils_test.go @@ -37,12 +37,13 @@ var prEventTemplate = ` func TestGetGithubMetadata(t *testing.T) { repo, eventName, sha, event, runID := "chainlink", "merge_group", "a-sha", `{}`, "1234" + expectedRunURL := fmt.Sprintf("github.com/%s/actions/runs/%s", repo, runID) ctx := getGithubMetadata(repo, eventName, sha, strings.NewReader(event), runID) - assert.Equal(t, Context{Repository: repo, CommitSHA: sha, Type: eventName, RunURL: fmt.Sprintf("%s/actions/%s", repo, runID)}, ctx) + assert.Equal(t, Context{Repository: repo, CommitSHA: sha, Type: eventName, RunURL: expectedRunURL}, ctx) anotherSha, eventName, url := "another-sha", "pull_request", "a-url" event = fmt.Sprintf(prEventTemplate, anotherSha, url) sha = "302eb05d592132309b264e316f443f1ceb81b6c3" ctx = getGithubMetadata(repo, eventName, sha, strings.NewReader(event), runID) - assert.Equal(t, Context{Repository: repo, CommitSHA: anotherSha, Type: eventName, PullRequestURL: url, RunURL: fmt.Sprintf("%s/actions/%s", repo, runID)}, ctx) + assert.Equal(t, Context{Repository: repo, CommitSHA: anotherSha, Type: eventName, PullRequestURL: url, RunURL: expectedRunURL}, ctx) } From 5dea552b46533c687b804a40fbed433868732f0b Mon Sep 17 00:00:00 2001 From: Dmytro Haidashenko <34754799+dhaidashenko@users.noreply.github.com> Date: Thu, 9 Nov 2023 21:04:30 +0100 Subject: [PATCH 4/7] Generalized Multinode unit tests BCI-2283 (#11066) * POC for generalized multinode tests * sendOnly node tests * multi node tests * node fsm test & node aliveLoop * node lifecycle tests * increase test coverage * fixed flakey tests * fixed rebase artifacts * nit fixes * regen mocks * review fixes * replace core/testutils with `chainlink-relay/pkg/utils/tests` * Apply suggestions from code review Co-authored-by: Jordan Krage Co-authored-by: Dimitris Grigoriou * update chainlink-relay * make gomodtidy * Update common/client/send_only_node_test.go Co-authored-by: Dimitris Grigoriou * simplify node state check * sendOnly & node tests fixes * make gomodtidy * fix deps * update relay * fix silly cleanup issue * Apply suggestions from code review Co-authored-by: Dimitris Grigoriou * review fixes --------- Co-authored-by: Jordan Krage Co-authored-by: Dimitris Grigoriou --- common/client/mock_hashable_test.go | 18 + common/client/mock_head_test.go | 57 + common/client/mock_node_client_test.go | 168 +++ common/client/mock_node_selector_test.go | 57 + common/client/mock_node_test.go | 195 +++ common/client/mock_rpc_test.go | 608 ++++++++++ common/client/mock_send_only_client_test.go | 72 ++ common/client/mock_send_only_node_test.go | 127 ++ common/client/multi_node.go | 44 +- common/client/multi_node_test.go | 635 ++++++++++ common/client/node.go | 25 +- common/client/node_fsm_test.go | 108 ++ common/client/node_lifecycle.go | 12 +- common/client/node_lifecycle_test.go | 1070 +++++++++++++++++ common/client/node_selector.go | 46 + .../client/node_selector_highest_head_test.go | 176 +++ .../node_selector_priority_level_test.go | 88 ++ .../client/node_selector_round_robin_test.go | 61 + common/client/node_selector_test.go | 18 + .../node_selector_total_difficulty_test.go | 178 +++ common/client/node_test.go | 80 ++ common/client/send_only_node.go | 4 + common/client/send_only_node_test.go | 139 +++ common/client/types.go | 6 + common/types/test_utils.go | 16 + 25 files changed, 3956 insertions(+), 52 deletions(-) create mode 100644 common/client/mock_hashable_test.go create mode 100644 common/client/mock_head_test.go create mode 100644 common/client/mock_node_client_test.go create mode 100644 common/client/mock_node_selector_test.go create mode 100644 common/client/mock_node_test.go create mode 100644 common/client/mock_rpc_test.go create mode 100644 common/client/mock_send_only_client_test.go create mode 100644 common/client/mock_send_only_node_test.go create mode 100644 common/client/multi_node_test.go create mode 100644 common/client/node_fsm_test.go create mode 100644 common/client/node_lifecycle_test.go create mode 100644 common/client/node_selector.go create mode 100644 common/client/node_selector_highest_head_test.go create mode 100644 common/client/node_selector_priority_level_test.go create mode 100644 common/client/node_selector_round_robin_test.go create mode 100644 common/client/node_selector_test.go create mode 100644 common/client/node_selector_total_difficulty_test.go create mode 100644 common/client/node_test.go create mode 100644 common/client/send_only_node_test.go create mode 100644 common/types/test_utils.go diff --git a/common/client/mock_hashable_test.go b/common/client/mock_hashable_test.go new file mode 100644 index 00000000000..d9f1670c073 --- /dev/null +++ b/common/client/mock_hashable_test.go @@ -0,0 +1,18 @@ +package client + +import "cmp" + +// Hashable - simple implementation of types.Hashable interface to be used as concrete type in tests +type Hashable string + +func (h Hashable) Cmp(c Hashable) int { + return cmp.Compare(h, c) +} + +func (h Hashable) String() string { + return string(h) +} + +func (h Hashable) Bytes() []byte { + return []byte(h) +} diff --git a/common/client/mock_head_test.go b/common/client/mock_head_test.go new file mode 100644 index 00000000000..b9cf0a5866f --- /dev/null +++ b/common/client/mock_head_test.go @@ -0,0 +1,57 @@ +// Code generated by mockery v2.35.4. DO NOT EDIT. + +package client + +import ( + utils "github.com/smartcontractkit/chainlink/v2/core/utils" + mock "github.com/stretchr/testify/mock" +) + +// mockHead is an autogenerated mock type for the Head type +type mockHead struct { + mock.Mock +} + +// BlockDifficulty provides a mock function with given fields: +func (_m *mockHead) BlockDifficulty() *utils.Big { + ret := _m.Called() + + var r0 *utils.Big + if rf, ok := ret.Get(0).(func() *utils.Big); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*utils.Big) + } + } + + return r0 +} + +// BlockNumber provides a mock function with given fields: +func (_m *mockHead) BlockNumber() int64 { + ret := _m.Called() + + var r0 int64 + if rf, ok := ret.Get(0).(func() int64); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int64) + } + + return r0 +} + +// newMockHead creates a new instance of mockHead. 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 newMockHead(t interface { + mock.TestingT + Cleanup(func()) +}) *mockHead { + mock := &mockHead{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/common/client/mock_node_client_test.go b/common/client/mock_node_client_test.go new file mode 100644 index 00000000000..7c8eb69171f --- /dev/null +++ b/common/client/mock_node_client_test.go @@ -0,0 +1,168 @@ +// Code generated by mockery v2.35.4. DO NOT EDIT. + +package client + +import ( + context "context" + + types "github.com/smartcontractkit/chainlink/v2/common/types" + mock "github.com/stretchr/testify/mock" +) + +// mockNodeClient is an autogenerated mock type for the NodeClient type +type mockNodeClient[CHAIN_ID types.ID, HEAD Head] struct { + mock.Mock +} + +// ChainID provides a mock function with given fields: ctx +func (_m *mockNodeClient[CHAIN_ID, HEAD]) ChainID(ctx context.Context) (CHAIN_ID, error) { + ret := _m.Called(ctx) + + var r0 CHAIN_ID + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (CHAIN_ID, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) CHAIN_ID); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(CHAIN_ID) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ClientVersion provides a mock function with given fields: _a0 +func (_m *mockNodeClient[CHAIN_ID, HEAD]) ClientVersion(_a0 context.Context) (string, error) { + ret := _m.Called(_a0) + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (string, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) string); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Close provides a mock function with given fields: +func (_m *mockNodeClient[CHAIN_ID, HEAD]) Close() { + _m.Called() +} + +// Dial provides a mock function with given fields: ctx +func (_m *mockNodeClient[CHAIN_ID, HEAD]) Dial(ctx context.Context) error { + ret := _m.Called(ctx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DialHTTP provides a mock function with given fields: +func (_m *mockNodeClient[CHAIN_ID, HEAD]) DialHTTP() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DisconnectAll provides a mock function with given fields: +func (_m *mockNodeClient[CHAIN_ID, HEAD]) DisconnectAll() { + _m.Called() +} + +// SetAliveLoopSub provides a mock function with given fields: _a0 +func (_m *mockNodeClient[CHAIN_ID, HEAD]) SetAliveLoopSub(_a0 types.Subscription) { + _m.Called(_a0) +} + +// Subscribe provides a mock function with given fields: ctx, channel, args +func (_m *mockNodeClient[CHAIN_ID, HEAD]) Subscribe(ctx context.Context, channel chan<- HEAD, args ...interface{}) (types.Subscription, error) { + var _ca []interface{} + _ca = append(_ca, ctx, channel) + _ca = append(_ca, args...) + ret := _m.Called(_ca...) + + var r0 types.Subscription + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, chan<- HEAD, ...interface{}) (types.Subscription, error)); ok { + return rf(ctx, channel, args...) + } + if rf, ok := ret.Get(0).(func(context.Context, chan<- HEAD, ...interface{}) types.Subscription); ok { + r0 = rf(ctx, channel, args...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.Subscription) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, chan<- HEAD, ...interface{}) error); ok { + r1 = rf(ctx, channel, args...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// SubscribersCount provides a mock function with given fields: +func (_m *mockNodeClient[CHAIN_ID, HEAD]) SubscribersCount() int32 { + ret := _m.Called() + + var r0 int32 + if rf, ok := ret.Get(0).(func() int32); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int32) + } + + return r0 +} + +// UnsubscribeAllExceptAliveLoop provides a mock function with given fields: +func (_m *mockNodeClient[CHAIN_ID, HEAD]) UnsubscribeAllExceptAliveLoop() { + _m.Called() +} + +// newMockNodeClient creates a new instance of mockNodeClient. 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 newMockNodeClient[CHAIN_ID types.ID, HEAD Head](t interface { + mock.TestingT + Cleanup(func()) +}) *mockNodeClient[CHAIN_ID, HEAD] { + mock := &mockNodeClient[CHAIN_ID, HEAD]{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/common/client/mock_node_selector_test.go b/common/client/mock_node_selector_test.go new file mode 100644 index 00000000000..e7b8d9ecb8d --- /dev/null +++ b/common/client/mock_node_selector_test.go @@ -0,0 +1,57 @@ +// Code generated by mockery v2.35.4. DO NOT EDIT. + +package client + +import ( + types "github.com/smartcontractkit/chainlink/v2/common/types" + mock "github.com/stretchr/testify/mock" +) + +// mockNodeSelector is an autogenerated mock type for the NodeSelector type +type mockNodeSelector[CHAIN_ID types.ID, HEAD Head, RPC NodeClient[CHAIN_ID, HEAD]] struct { + mock.Mock +} + +// Name provides a mock function with given fields: +func (_m *mockNodeSelector[CHAIN_ID, HEAD, RPC]) Name() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Select provides a mock function with given fields: +func (_m *mockNodeSelector[CHAIN_ID, HEAD, RPC]) Select() Node[CHAIN_ID, HEAD, RPC] { + ret := _m.Called() + + var r0 Node[CHAIN_ID, HEAD, RPC] + if rf, ok := ret.Get(0).(func() Node[CHAIN_ID, HEAD, RPC]); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(Node[CHAIN_ID, HEAD, RPC]) + } + } + + return r0 +} + +// newMockNodeSelector creates a new instance of mockNodeSelector. 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 newMockNodeSelector[CHAIN_ID types.ID, HEAD Head, RPC NodeClient[CHAIN_ID, HEAD]](t interface { + mock.TestingT + Cleanup(func()) +}) *mockNodeSelector[CHAIN_ID, HEAD, RPC] { + mock := &mockNodeSelector[CHAIN_ID, HEAD, RPC]{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/common/client/mock_node_test.go b/common/client/mock_node_test.go new file mode 100644 index 00000000000..bd704cd2c6f --- /dev/null +++ b/common/client/mock_node_test.go @@ -0,0 +1,195 @@ +// Code generated by mockery v2.35.4. DO NOT EDIT. + +package client + +import ( + context "context" + + types "github.com/smartcontractkit/chainlink/v2/common/types" + mock "github.com/stretchr/testify/mock" + + utils "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +// mockNode is an autogenerated mock type for the Node type +type mockNode[CHAIN_ID types.ID, HEAD Head, RPC NodeClient[CHAIN_ID, HEAD]] struct { + mock.Mock +} + +// Close provides a mock function with given fields: +func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Close() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ConfiguredChainID provides a mock function with given fields: +func (_m *mockNode[CHAIN_ID, HEAD, RPC]) ConfiguredChainID() CHAIN_ID { + ret := _m.Called() + + var r0 CHAIN_ID + if rf, ok := ret.Get(0).(func() CHAIN_ID); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(CHAIN_ID) + } + + return r0 +} + +// Name provides a mock function with given fields: +func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Name() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Order provides a mock function with given fields: +func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Order() int32 { + ret := _m.Called() + + var r0 int32 + if rf, ok := ret.Get(0).(func() int32); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int32) + } + + return r0 +} + +// RPC provides a mock function with given fields: +func (_m *mockNode[CHAIN_ID, HEAD, RPC]) RPC() RPC { + ret := _m.Called() + + var r0 RPC + if rf, ok := ret.Get(0).(func() RPC); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(RPC) + } + + return r0 +} + +// Start provides a mock function with given fields: _a0 +func (_m *mockNode[CHAIN_ID, HEAD, RPC]) Start(_a0 context.Context) error { + ret := _m.Called(_a0) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// State provides a mock function with given fields: +func (_m *mockNode[CHAIN_ID, HEAD, RPC]) State() nodeState { + ret := _m.Called() + + var r0 nodeState + if rf, ok := ret.Get(0).(func() nodeState); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(nodeState) + } + + return r0 +} + +// StateAndLatest provides a mock function with given fields: +func (_m *mockNode[CHAIN_ID, HEAD, RPC]) StateAndLatest() (nodeState, int64, *utils.Big) { + ret := _m.Called() + + var r0 nodeState + var r1 int64 + var r2 *utils.Big + if rf, ok := ret.Get(0).(func() (nodeState, int64, *utils.Big)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() nodeState); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(nodeState) + } + + if rf, ok := ret.Get(1).(func() int64); ok { + r1 = rf() + } else { + r1 = ret.Get(1).(int64) + } + + if rf, ok := ret.Get(2).(func() *utils.Big); ok { + r2 = rf() + } else { + if ret.Get(2) != nil { + r2 = ret.Get(2).(*utils.Big) + } + } + + return r0, r1, r2 +} + +// String provides a mock function with given fields: +func (_m *mockNode[CHAIN_ID, HEAD, RPC]) String() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// SubscribersCount provides a mock function with given fields: +func (_m *mockNode[CHAIN_ID, HEAD, RPC]) SubscribersCount() int32 { + ret := _m.Called() + + var r0 int32 + if rf, ok := ret.Get(0).(func() int32); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int32) + } + + return r0 +} + +// UnsubscribeAllExceptAliveLoop provides a mock function with given fields: +func (_m *mockNode[CHAIN_ID, HEAD, RPC]) UnsubscribeAllExceptAliveLoop() { + _m.Called() +} + +// newMockNode creates a new instance of mockNode. 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 newMockNode[CHAIN_ID types.ID, HEAD Head, RPC NodeClient[CHAIN_ID, HEAD]](t interface { + mock.TestingT + Cleanup(func()) +}) *mockNode[CHAIN_ID, HEAD, RPC] { + mock := &mockNode[CHAIN_ID, HEAD, RPC]{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/common/client/mock_rpc_test.go b/common/client/mock_rpc_test.go new file mode 100644 index 00000000000..c378b9384e4 --- /dev/null +++ b/common/client/mock_rpc_test.go @@ -0,0 +1,608 @@ +// Code generated by mockery v2.35.4. DO NOT EDIT. + +package client + +import ( + big "math/big" + + assets "github.com/smartcontractkit/chainlink/v2/core/assets" + + context "context" + + feetypes "github.com/smartcontractkit/chainlink/v2/common/fee/types" + + mock "github.com/stretchr/testify/mock" + + types "github.com/smartcontractkit/chainlink/v2/common/types" +) + +// mockRPC is an autogenerated mock type for the RPC type +type mockRPC[CHAIN_ID types.ID, SEQ types.Sequence, ADDR types.Hashable, BLOCK_HASH types.Hashable, TX interface{}, TX_HASH types.Hashable, EVENT interface{}, EVENT_OPS interface{}, TX_RECEIPT types.Receipt[TX_HASH, BLOCK_HASH], FEE feetypes.Fee, HEAD types.Head[BLOCK_HASH]] struct { + mock.Mock +} + +// BalanceAt provides a mock function with given fields: ctx, accountAddress, blockNumber +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) BalanceAt(ctx context.Context, accountAddress ADDR, blockNumber *big.Int) (*big.Int, error) { + ret := _m.Called(ctx, accountAddress, blockNumber) + + var r0 *big.Int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ADDR, *big.Int) (*big.Int, error)); ok { + return rf(ctx, accountAddress, blockNumber) + } + if rf, ok := ret.Get(0).(func(context.Context, ADDR, *big.Int) *big.Int); ok { + r0 = rf(ctx, accountAddress, blockNumber) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*big.Int) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ADDR, *big.Int) error); ok { + r1 = rf(ctx, accountAddress, blockNumber) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BatchCallContext provides a mock function with given fields: ctx, b +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) BatchCallContext(ctx context.Context, b []interface{}) error { + ret := _m.Called(ctx, b) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, []interface{}) error); ok { + r0 = rf(ctx, b) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// BlockByHash provides a mock function with given fields: ctx, hash +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) BlockByHash(ctx context.Context, hash BLOCK_HASH) (HEAD, error) { + ret := _m.Called(ctx, hash) + + var r0 HEAD + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, BLOCK_HASH) (HEAD, error)); ok { + return rf(ctx, hash) + } + if rf, ok := ret.Get(0).(func(context.Context, BLOCK_HASH) HEAD); ok { + r0 = rf(ctx, hash) + } else { + r0 = ret.Get(0).(HEAD) + } + + if rf, ok := ret.Get(1).(func(context.Context, BLOCK_HASH) error); ok { + r1 = rf(ctx, hash) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// BlockByNumber provides a mock function with given fields: ctx, number +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) BlockByNumber(ctx context.Context, number *big.Int) (HEAD, error) { + ret := _m.Called(ctx, number) + + var r0 HEAD + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) (HEAD, error)); ok { + return rf(ctx, number) + } + if rf, ok := ret.Get(0).(func(context.Context, *big.Int) HEAD); ok { + r0 = rf(ctx, number) + } else { + r0 = ret.Get(0).(HEAD) + } + + if rf, ok := ret.Get(1).(func(context.Context, *big.Int) error); ok { + r1 = rf(ctx, number) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// CallContext provides a mock function with given fields: ctx, result, method, args +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) CallContext(ctx context.Context, result interface{}, method string, args ...interface{}) error { + var _ca []interface{} + _ca = append(_ca, ctx, result, method) + _ca = append(_ca, args...) + ret := _m.Called(_ca...) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, interface{}, string, ...interface{}) error); ok { + r0 = rf(ctx, result, method, args...) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// CallContract provides a mock function with given fields: ctx, msg, blockNumber +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) CallContract(ctx context.Context, msg interface{}, blockNumber *big.Int) ([]byte, error) { + ret := _m.Called(ctx, msg, blockNumber) + + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, interface{}, *big.Int) ([]byte, error)); ok { + return rf(ctx, msg, blockNumber) + } + if rf, ok := ret.Get(0).(func(context.Context, interface{}, *big.Int) []byte); ok { + r0 = rf(ctx, msg, blockNumber) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, interface{}, *big.Int) error); ok { + r1 = rf(ctx, msg, blockNumber) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ChainID provides a mock function with given fields: ctx +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) ChainID(ctx context.Context) (CHAIN_ID, error) { + ret := _m.Called(ctx) + + var r0 CHAIN_ID + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (CHAIN_ID, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) CHAIN_ID); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(CHAIN_ID) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ClientVersion provides a mock function with given fields: _a0 +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) ClientVersion(_a0 context.Context) (string, error) { + ret := _m.Called(_a0) + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (string, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) string); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Close provides a mock function with given fields: +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) Close() { + _m.Called() +} + +// CodeAt provides a mock function with given fields: ctx, account, blockNumber +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) CodeAt(ctx context.Context, account ADDR, blockNumber *big.Int) ([]byte, error) { + ret := _m.Called(ctx, account, blockNumber) + + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ADDR, *big.Int) ([]byte, error)); ok { + return rf(ctx, account, blockNumber) + } + if rf, ok := ret.Get(0).(func(context.Context, ADDR, *big.Int) []byte); ok { + r0 = rf(ctx, account, blockNumber) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ADDR, *big.Int) error); ok { + r1 = rf(ctx, account, blockNumber) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Dial provides a mock function with given fields: ctx +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) Dial(ctx context.Context) error { + ret := _m.Called(ctx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DialHTTP provides a mock function with given fields: +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) DialHTTP() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DisconnectAll provides a mock function with given fields: +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) DisconnectAll() { + _m.Called() +} + +// EstimateGas provides a mock function with given fields: ctx, call +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) EstimateGas(ctx context.Context, call interface{}) (uint64, error) { + ret := _m.Called(ctx, call) + + var r0 uint64 + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, interface{}) (uint64, error)); ok { + return rf(ctx, call) + } + if rf, ok := ret.Get(0).(func(context.Context, interface{}) uint64); ok { + r0 = rf(ctx, call) + } else { + r0 = ret.Get(0).(uint64) + } + + if rf, ok := ret.Get(1).(func(context.Context, interface{}) error); ok { + r1 = rf(ctx, call) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// FilterEvents provides a mock function with given fields: ctx, query +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) FilterEvents(ctx context.Context, query EVENT_OPS) ([]EVENT, error) { + ret := _m.Called(ctx, query) + + var r0 []EVENT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, EVENT_OPS) ([]EVENT, error)); ok { + return rf(ctx, query) + } + if rf, ok := ret.Get(0).(func(context.Context, EVENT_OPS) []EVENT); ok { + r0 = rf(ctx, query) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]EVENT) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, EVENT_OPS) error); ok { + r1 = rf(ctx, query) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LINKBalance provides a mock function with given fields: ctx, accountAddress, linkAddress +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) LINKBalance(ctx context.Context, accountAddress ADDR, linkAddress ADDR) (*assets.Link, error) { + ret := _m.Called(ctx, accountAddress, linkAddress) + + var r0 *assets.Link + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ADDR, ADDR) (*assets.Link, error)); ok { + return rf(ctx, accountAddress, linkAddress) + } + if rf, ok := ret.Get(0).(func(context.Context, ADDR, ADDR) *assets.Link); ok { + r0 = rf(ctx, accountAddress, linkAddress) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*assets.Link) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ADDR, ADDR) error); ok { + r1 = rf(ctx, accountAddress, linkAddress) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// LatestBlockHeight provides a mock function with given fields: _a0 +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) LatestBlockHeight(_a0 context.Context) (*big.Int, error) { + ret := _m.Called(_a0) + + var r0 *big.Int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*big.Int, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) *big.Int); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*big.Int) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// PendingSequenceAt provides a mock function with given fields: ctx, addr +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) PendingSequenceAt(ctx context.Context, addr ADDR) (SEQ, error) { + ret := _m.Called(ctx, addr) + + var r0 SEQ + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ADDR) (SEQ, error)); ok { + return rf(ctx, addr) + } + if rf, ok := ret.Get(0).(func(context.Context, ADDR) SEQ); ok { + r0 = rf(ctx, addr) + } else { + r0 = ret.Get(0).(SEQ) + } + + if rf, ok := ret.Get(1).(func(context.Context, ADDR) error); ok { + r1 = rf(ctx, addr) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// SendEmptyTransaction provides a mock function with given fields: ctx, newTxAttempt, seq, gasLimit, fee, fromAddress +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) SendEmptyTransaction(ctx context.Context, newTxAttempt func(SEQ, uint32, FEE, ADDR) (interface{}, error), seq SEQ, gasLimit uint32, fee FEE, fromAddress ADDR) (string, error) { + ret := _m.Called(ctx, newTxAttempt, seq, gasLimit, fee, fromAddress) + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, func(SEQ, uint32, FEE, ADDR) (interface{}, error), SEQ, uint32, FEE, ADDR) (string, error)); ok { + return rf(ctx, newTxAttempt, seq, gasLimit, fee, fromAddress) + } + if rf, ok := ret.Get(0).(func(context.Context, func(SEQ, uint32, FEE, ADDR) (interface{}, error), SEQ, uint32, FEE, ADDR) string); ok { + r0 = rf(ctx, newTxAttempt, seq, gasLimit, fee, fromAddress) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(context.Context, func(SEQ, uint32, FEE, ADDR) (interface{}, error), SEQ, uint32, FEE, ADDR) error); ok { + r1 = rf(ctx, newTxAttempt, seq, gasLimit, fee, fromAddress) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// SendTransaction provides a mock function with given fields: ctx, tx +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) SendTransaction(ctx context.Context, tx TX) error { + ret := _m.Called(ctx, tx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, TX) error); ok { + r0 = rf(ctx, tx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// SequenceAt provides a mock function with given fields: ctx, accountAddress, blockNumber +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) SequenceAt(ctx context.Context, accountAddress ADDR, blockNumber *big.Int) (SEQ, error) { + ret := _m.Called(ctx, accountAddress, blockNumber) + + var r0 SEQ + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ADDR, *big.Int) (SEQ, error)); ok { + return rf(ctx, accountAddress, blockNumber) + } + if rf, ok := ret.Get(0).(func(context.Context, ADDR, *big.Int) SEQ); ok { + r0 = rf(ctx, accountAddress, blockNumber) + } else { + r0 = ret.Get(0).(SEQ) + } + + if rf, ok := ret.Get(1).(func(context.Context, ADDR, *big.Int) error); ok { + r1 = rf(ctx, accountAddress, blockNumber) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// SetAliveLoopSub provides a mock function with given fields: _a0 +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) SetAliveLoopSub(_a0 types.Subscription) { + _m.Called(_a0) +} + +// SimulateTransaction provides a mock function with given fields: ctx, tx +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) SimulateTransaction(ctx context.Context, tx TX) error { + ret := _m.Called(ctx, tx) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, TX) error); ok { + r0 = rf(ctx, tx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Subscribe provides a mock function with given fields: ctx, channel, args +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) Subscribe(ctx context.Context, channel chan<- HEAD, args ...interface{}) (types.Subscription, error) { + var _ca []interface{} + _ca = append(_ca, ctx, channel) + _ca = append(_ca, args...) + ret := _m.Called(_ca...) + + var r0 types.Subscription + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, chan<- HEAD, ...interface{}) (types.Subscription, error)); ok { + return rf(ctx, channel, args...) + } + if rf, ok := ret.Get(0).(func(context.Context, chan<- HEAD, ...interface{}) types.Subscription); ok { + r0 = rf(ctx, channel, args...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(types.Subscription) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, chan<- HEAD, ...interface{}) error); ok { + r1 = rf(ctx, channel, args...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// SubscribersCount provides a mock function with given fields: +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) SubscribersCount() int32 { + ret := _m.Called() + + var r0 int32 + if rf, ok := ret.Get(0).(func() int32); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int32) + } + + return r0 +} + +// TokenBalance provides a mock function with given fields: ctx, accountAddress, tokenAddress +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) TokenBalance(ctx context.Context, accountAddress ADDR, tokenAddress ADDR) (*big.Int, error) { + ret := _m.Called(ctx, accountAddress, tokenAddress) + + var r0 *big.Int + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, ADDR, ADDR) (*big.Int, error)); ok { + return rf(ctx, accountAddress, tokenAddress) + } + if rf, ok := ret.Get(0).(func(context.Context, ADDR, ADDR) *big.Int); ok { + r0 = rf(ctx, accountAddress, tokenAddress) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*big.Int) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, ADDR, ADDR) error); ok { + r1 = rf(ctx, accountAddress, tokenAddress) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// TransactionByHash provides a mock function with given fields: ctx, txHash +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) TransactionByHash(ctx context.Context, txHash TX_HASH) (TX, error) { + ret := _m.Called(ctx, txHash) + + var r0 TX + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, TX_HASH) (TX, error)); ok { + return rf(ctx, txHash) + } + if rf, ok := ret.Get(0).(func(context.Context, TX_HASH) TX); ok { + r0 = rf(ctx, txHash) + } else { + r0 = ret.Get(0).(TX) + } + + if rf, ok := ret.Get(1).(func(context.Context, TX_HASH) error); ok { + r1 = rf(ctx, txHash) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// TransactionReceipt provides a mock function with given fields: ctx, txHash +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) TransactionReceipt(ctx context.Context, txHash TX_HASH) (TX_RECEIPT, error) { + ret := _m.Called(ctx, txHash) + + var r0 TX_RECEIPT + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, TX_HASH) (TX_RECEIPT, error)); ok { + return rf(ctx, txHash) + } + if rf, ok := ret.Get(0).(func(context.Context, TX_HASH) TX_RECEIPT); ok { + r0 = rf(ctx, txHash) + } else { + r0 = ret.Get(0).(TX_RECEIPT) + } + + if rf, ok := ret.Get(1).(func(context.Context, TX_HASH) error); ok { + r1 = rf(ctx, txHash) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// UnsubscribeAllExceptAliveLoop provides a mock function with given fields: +func (_m *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]) UnsubscribeAllExceptAliveLoop() { + _m.Called() +} + +// newMockRPC creates a new instance of mockRPC. 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 newMockRPC[CHAIN_ID types.ID, SEQ types.Sequence, ADDR types.Hashable, BLOCK_HASH types.Hashable, TX interface{}, TX_HASH types.Hashable, EVENT interface{}, EVENT_OPS interface{}, TX_RECEIPT types.Receipt[TX_HASH, BLOCK_HASH], FEE feetypes.Fee, HEAD types.Head[BLOCK_HASH]](t interface { + mock.TestingT + Cleanup(func()) +}) *mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD] { + mock := &mockRPC[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD]{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/common/client/mock_send_only_client_test.go b/common/client/mock_send_only_client_test.go new file mode 100644 index 00000000000..481b2602ea3 --- /dev/null +++ b/common/client/mock_send_only_client_test.go @@ -0,0 +1,72 @@ +// Code generated by mockery v2.35.4. DO NOT EDIT. + +package client + +import ( + context "context" + + types "github.com/smartcontractkit/chainlink/v2/common/types" + mock "github.com/stretchr/testify/mock" +) + +// mockSendOnlyClient is an autogenerated mock type for the sendOnlyClient type +type mockSendOnlyClient[CHAIN_ID types.ID] struct { + mock.Mock +} + +// ChainID provides a mock function with given fields: _a0 +func (_m *mockSendOnlyClient[CHAIN_ID]) ChainID(_a0 context.Context) (CHAIN_ID, error) { + ret := _m.Called(_a0) + + var r0 CHAIN_ID + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (CHAIN_ID, error)); ok { + return rf(_a0) + } + if rf, ok := ret.Get(0).(func(context.Context) CHAIN_ID); ok { + r0 = rf(_a0) + } else { + r0 = ret.Get(0).(CHAIN_ID) + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(_a0) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Close provides a mock function with given fields: +func (_m *mockSendOnlyClient[CHAIN_ID]) Close() { + _m.Called() +} + +// DialHTTP provides a mock function with given fields: +func (_m *mockSendOnlyClient[CHAIN_ID]) DialHTTP() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// newMockSendOnlyClient creates a new instance of mockSendOnlyClient. 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 newMockSendOnlyClient[CHAIN_ID types.ID](t interface { + mock.TestingT + Cleanup(func()) +}) *mockSendOnlyClient[CHAIN_ID] { + mock := &mockSendOnlyClient[CHAIN_ID]{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/common/client/mock_send_only_node_test.go b/common/client/mock_send_only_node_test.go new file mode 100644 index 00000000000..524d7d8a6c5 --- /dev/null +++ b/common/client/mock_send_only_node_test.go @@ -0,0 +1,127 @@ +// Code generated by mockery v2.35.4. DO NOT EDIT. + +package client + +import ( + context "context" + + types "github.com/smartcontractkit/chainlink/v2/common/types" + mock "github.com/stretchr/testify/mock" +) + +// mockSendOnlyNode is an autogenerated mock type for the SendOnlyNode type +type mockSendOnlyNode[CHAIN_ID types.ID, RPC sendOnlyClient[CHAIN_ID]] struct { + mock.Mock +} + +// Close provides a mock function with given fields: +func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) Close() error { + ret := _m.Called() + + var r0 error + if rf, ok := ret.Get(0).(func() error); ok { + r0 = rf() + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ConfiguredChainID provides a mock function with given fields: +func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) ConfiguredChainID() CHAIN_ID { + ret := _m.Called() + + var r0 CHAIN_ID + if rf, ok := ret.Get(0).(func() CHAIN_ID); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(CHAIN_ID) + } + + return r0 +} + +// Name provides a mock function with given fields: +func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) Name() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// RPC provides a mock function with given fields: +func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) RPC() RPC { + ret := _m.Called() + + var r0 RPC + if rf, ok := ret.Get(0).(func() RPC); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(RPC) + } + + return r0 +} + +// Start provides a mock function with given fields: _a0 +func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) Start(_a0 context.Context) error { + ret := _m.Called(_a0) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// State provides a mock function with given fields: +func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) State() nodeState { + ret := _m.Called() + + var r0 nodeState + if rf, ok := ret.Get(0).(func() nodeState); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(nodeState) + } + + return r0 +} + +// String provides a mock function with given fields: +func (_m *mockSendOnlyNode[CHAIN_ID, RPC]) String() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// newMockSendOnlyNode creates a new instance of mockSendOnlyNode. 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 newMockSendOnlyNode[CHAIN_ID types.ID, RPC sendOnlyClient[CHAIN_ID]](t interface { + mock.TestingT + Cleanup(func()) +}) *mockSendOnlyNode[CHAIN_ID, RPC] { + mock := &mockSendOnlyNode[CHAIN_ID, RPC]{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/common/client/multi_node.go b/common/client/multi_node.go index f54e3115d95..c268cfb23cd 100644 --- a/common/client/multi_node.go +++ b/common/client/multi_node.go @@ -30,25 +30,6 @@ var ( ErroringNodeError = fmt.Errorf("no live nodes available") ) -const ( - NodeSelectionModeHighestHead = "HighestHead" - NodeSelectionModeRoundRobin = "RoundRobin" - NodeSelectionModeTotalDifficulty = "TotalDifficulty" - NodeSelectionModePriorityLevel = "PriorityLevel" -) - -type NodeSelector[ - CHAIN_ID types.ID, - HEAD Head, - RPC NodeClient[CHAIN_ID, HEAD], -] interface { - // Select returns a Node, or nil if none can be selected. - // Implementation must be thread-safe. - Select() Node[CHAIN_ID, HEAD, RPC] - // Name returns the strategy name, e.g. "HighestHead" or "RoundRobin" - Name() string -} - // MultiNode is a generalized multi node client interface that includes methods to interact with different chains. // It also handles multiple node RPC connections simultaneously. type MultiNode[ @@ -113,6 +94,7 @@ type multiNode[ leaseDuration time.Duration leaseTicker *time.Ticker chainFamily string + reportInterval time.Duration activeMu sync.RWMutex activeNode Node[CHAIN_ID, HEAD, RPC_CLIENT] @@ -148,23 +130,13 @@ func NewMultiNode[ chainFamily string, sendOnlyErrorParser func(err error) SendTxReturnCode, ) MultiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT] { - nodeSelector := func() NodeSelector[CHAIN_ID, HEAD, RPC_CLIENT] { - switch selectionMode { - case NodeSelectionModeHighestHead: - return NewHighestHeadNodeSelector[CHAIN_ID, HEAD, RPC_CLIENT](nodes) - case NodeSelectionModeRoundRobin: - return NewRoundRobinSelector[CHAIN_ID, HEAD, RPC_CLIENT](nodes) - case NodeSelectionModeTotalDifficulty: - return NewTotalDifficultyNodeSelector[CHAIN_ID, HEAD, RPC_CLIENT](nodes) - case NodeSelectionModePriorityLevel: - return NewPriorityLevelNodeSelector[CHAIN_ID, HEAD, RPC_CLIENT](nodes) - default: - panic(fmt.Sprintf("unsupported NodeSelectionMode: %s", selectionMode)) - } - }() + nodeSelector := newNodeSelector(selectionMode, nodes) lggr := logger.Named("MultiNode").With("chainID", chainID.String()) + // Prometheus' default interval is 15s, set this to under 7.5s to avoid + // aliasing (see: https://en.wikipedia.org/wiki/Nyquist_frequency) + const reportInterval = 6500 * time.Millisecond c := &multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OPS, TX_RECEIPT, FEE, HEAD, RPC_CLIENT]{ nodes: nodes, sendonlys: sendonlys, @@ -178,6 +150,7 @@ func NewMultiNode[ leaseDuration: leaseDuration, chainFamily: chainFamily, sendOnlyErrorParser: sendOnlyErrorParser, + reportInterval: reportInterval, } c.logger.Debugf("The MultiNode is configured to use NodeSelectionMode: %s", selectionMode) @@ -341,10 +314,7 @@ func (c *multiNode[CHAIN_ID, SEQ, ADDR, BLOCK_HASH, TX, TX_HASH, EVENT, EVENT_OP c.report() - // Prometheus' default interval is 15s, set this to under 7.5s to avoid - // aliasing (see: https://en.wikipedia.org/wiki/Nyquist_frequency) - reportInterval := 6500 * time.Millisecond - monitor := time.NewTicker(utils.WithJitter(reportInterval)) + monitor := time.NewTicker(utils.WithJitter(c.reportInterval)) defer monitor.Stop() for { diff --git a/common/client/multi_node_test.go b/common/client/multi_node_test.go new file mode 100644 index 00000000000..1fddbc3be3c --- /dev/null +++ b/common/client/multi_node_test.go @@ -0,0 +1,635 @@ +package client + +import ( + "fmt" + "math/rand" + "testing" + "time" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "go.uber.org/zap" + + "github.com/smartcontractkit/chainlink-relay/pkg/utils/tests" + + "github.com/smartcontractkit/chainlink/v2/common/types" + "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +type multiNodeRPCClient RPC[types.ID, *utils.Big, Hashable, Hashable, any, Hashable, any, any, + types.Receipt[Hashable, Hashable], Hashable, types.Head[Hashable]] + +type testMultiNode struct { + *multiNode[types.ID, *utils.Big, Hashable, Hashable, any, Hashable, any, any, + types.Receipt[Hashable, Hashable], Hashable, types.Head[Hashable], multiNodeRPCClient] +} + +type multiNodeOpts struct { + logger logger.Logger + selectionMode string + leaseDuration time.Duration + noNewHeadsThreshold time.Duration + nodes []Node[types.ID, types.Head[Hashable], multiNodeRPCClient] + sendonlys []SendOnlyNode[types.ID, multiNodeRPCClient] + chainID types.ID + chainType config.ChainType + chainFamily string + sendOnlyErrorParser func(err error) SendTxReturnCode +} + +func newTestMultiNode(t *testing.T, opts multiNodeOpts) testMultiNode { + if opts.logger == nil { + opts.logger = logger.TestLogger(t) + } + + result := NewMultiNode[types.ID, *utils.Big, Hashable, Hashable, any, Hashable, any, any, + types.Receipt[Hashable, Hashable], Hashable, types.Head[Hashable], multiNodeRPCClient](opts.logger, + opts.selectionMode, opts.leaseDuration, opts.noNewHeadsThreshold, opts.nodes, opts.sendonlys, + opts.chainID, opts.chainType, opts.chainFamily, opts.sendOnlyErrorParser) + return testMultiNode{ + result.(*multiNode[types.ID, *utils.Big, Hashable, Hashable, any, Hashable, any, any, + types.Receipt[Hashable, Hashable], Hashable, types.Head[Hashable], multiNodeRPCClient]), + } +} + +func newMultiNodeRPCClient(t *testing.T) *mockRPC[types.ID, *utils.Big, Hashable, Hashable, any, Hashable, any, any, + types.Receipt[Hashable, Hashable], Hashable, types.Head[Hashable]] { + return newMockRPC[types.ID, *utils.Big, Hashable, Hashable, any, Hashable, any, any, + types.Receipt[Hashable, Hashable], Hashable, types.Head[Hashable]](t) +} + +func newHealthyNode(t *testing.T, chainID types.ID) *mockNode[types.ID, types.Head[Hashable], multiNodeRPCClient] { + return newNodeWithState(t, chainID, nodeStateAlive) +} + +func newNodeWithState(t *testing.T, chainID types.ID, state nodeState) *mockNode[types.ID, types.Head[Hashable], multiNodeRPCClient] { + node := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + node.On("ConfiguredChainID").Return(chainID).Once() + node.On("Start", mock.Anything).Return(nil).Once() + node.On("Close").Return(nil).Once() + node.On("State").Return(state).Maybe() + node.On("String").Return(fmt.Sprintf("healthy_node_%d", rand.Int())).Maybe() + return node +} +func TestMultiNode_Dial(t *testing.T) { + t.Parallel() + + newMockNode := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient] + newMockSendOnlyNode := newMockSendOnlyNode[types.ID, multiNodeRPCClient] + + t.Run("Fails without nodes", func(t *testing.T) { + t.Parallel() + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: types.RandomID(), + }) + err := mn.Dial(tests.Context(t)) + assert.EqualError(t, err, fmt.Sprintf("no available nodes for chain %s", mn.chainID.String())) + }) + t.Run("Fails with wrong node's chainID", func(t *testing.T) { + t.Parallel() + node := newMockNode(t) + multiNodeChainID := types.NewIDFromInt(10) + nodeChainID := types.NewIDFromInt(11) + node.On("ConfiguredChainID").Return(nodeChainID).Twice() + const nodeName = "nodeName" + node.On("String").Return(nodeName).Once() + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: multiNodeChainID, + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{node}, + }) + err := mn.Dial(tests.Context(t)) + assert.EqualError(t, err, fmt.Sprintf("node %s has configured chain ID %s which does not match multinode configured chain ID of %s", nodeName, nodeChainID, mn.chainID)) + }) + t.Run("Fails if node fails", func(t *testing.T) { + t.Parallel() + node := newMockNode(t) + chainID := types.RandomID() + node.On("ConfiguredChainID").Return(chainID).Once() + expectedError := errors.New("failed to start node") + node.On("Start", mock.Anything).Return(expectedError).Once() + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: chainID, + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{node}, + }) + err := mn.Dial(tests.Context(t)) + assert.EqualError(t, err, expectedError.Error()) + }) + + t.Run("Closes started nodes on failure", func(t *testing.T) { + t.Parallel() + chainID := types.RandomID() + node1 := newHealthyNode(t, chainID) + node2 := newMockNode(t) + node2.On("ConfiguredChainID").Return(chainID).Once() + expectedError := errors.New("failed to start node") + node2.On("Start", mock.Anything).Return(expectedError).Once() + + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: chainID, + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{node1, node2}, + }) + err := mn.Dial(tests.Context(t)) + assert.EqualError(t, err, expectedError.Error()) + }) + t.Run("Fails with wrong send only node's chainID", func(t *testing.T) { + t.Parallel() + multiNodeChainID := types.NewIDFromInt(10) + node := newHealthyNode(t, multiNodeChainID) + sendOnly := newMockSendOnlyNode(t) + sendOnlyChainID := types.NewIDFromInt(11) + sendOnly.On("ConfiguredChainID").Return(sendOnlyChainID).Twice() + const sendOnlyName = "sendOnlyNodeName" + sendOnly.On("String").Return(sendOnlyName).Once() + + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: multiNodeChainID, + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{node}, + sendonlys: []SendOnlyNode[types.ID, multiNodeRPCClient]{sendOnly}, + }) + err := mn.Dial(tests.Context(t)) + assert.EqualError(t, err, fmt.Sprintf("sendonly node %s has configured chain ID %s which does not match multinode configured chain ID of %s", sendOnlyName, sendOnlyChainID, mn.chainID)) + }) + + newHealthySendOnly := func(t *testing.T, chainID types.ID) *mockSendOnlyNode[types.ID, multiNodeRPCClient] { + node := newMockSendOnlyNode(t) + node.On("ConfiguredChainID").Return(chainID).Once() + node.On("Start", mock.Anything).Return(nil).Once() + node.On("Close").Return(nil).Once() + return node + } + t.Run("Fails on send only node failure", func(t *testing.T) { + t.Parallel() + chainID := types.NewIDFromInt(10) + node := newHealthyNode(t, chainID) + sendOnly1 := newHealthySendOnly(t, chainID) + sendOnly2 := newMockSendOnlyNode(t) + sendOnly2.On("ConfiguredChainID").Return(chainID).Once() + expectedError := errors.New("failed to start send only node") + sendOnly2.On("Start", mock.Anything).Return(expectedError).Once() + + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: chainID, + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{node}, + sendonlys: []SendOnlyNode[types.ID, multiNodeRPCClient]{sendOnly1, sendOnly2}, + }) + err := mn.Dial(tests.Context(t)) + assert.EqualError(t, err, expectedError.Error()) + }) + t.Run("Starts successfully with healthy nodes", func(t *testing.T) { + t.Parallel() + chainID := types.NewIDFromInt(10) + node := newHealthyNode(t, chainID) + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: chainID, + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{node}, + sendonlys: []SendOnlyNode[types.ID, multiNodeRPCClient]{newHealthySendOnly(t, chainID)}, + }) + defer func() { assert.NoError(t, mn.Close()) }() + err := mn.Dial(tests.Context(t)) + require.NoError(t, err) + selectedNode, err := mn.selectNode() + require.NoError(t, err) + assert.Equal(t, node, selectedNode) + }) +} + +func TestMultiNode_Report(t *testing.T) { + t.Parallel() + t.Run("Dial starts periodical reporting", func(t *testing.T) { + t.Parallel() + chainID := types.RandomID() + node1 := newHealthyNode(t, chainID) + node2 := newNodeWithState(t, chainID, nodeStateOutOfSync) + lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: chainID, + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{node1, node2}, + logger: lggr, + }) + mn.reportInterval = tests.TestInterval + defer func() { assert.NoError(t, mn.Close()) }() + err := mn.Dial(tests.Context(t)) + require.NoError(t, err) + tests.AssertLogCountEventually(t, observedLogs, "At least one primary node is dead: 1/2 nodes are alive", 2) + }) + t.Run("Report critical error on all node failure", func(t *testing.T) { + t.Parallel() + chainID := types.RandomID() + node := newNodeWithState(t, chainID, nodeStateOutOfSync) + lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: chainID, + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{node}, + logger: lggr, + }) + mn.reportInterval = tests.TestInterval + defer func() { assert.NoError(t, mn.Close()) }() + err := mn.Dial(tests.Context(t)) + require.NoError(t, err) + tests.AssertLogCountEventually(t, observedLogs, "no primary nodes available: 0/1 nodes are alive", 2) + err = mn.Healthy() + require.Error(t, err) + assert.Contains(t, err.Error(), "no primary nodes available: 0/1 nodes are alive") + }) +} + +func TestMultiNode_CheckLease(t *testing.T) { + t.Parallel() + t.Run("Round robin disables lease check", func(t *testing.T) { + t.Parallel() + chainID := types.RandomID() + node := newHealthyNode(t, chainID) + lggr, observedLogs := logger.TestLoggerObserved(t, zap.InfoLevel) + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: chainID, + logger: lggr, + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{node}, + }) + defer func() { assert.NoError(t, mn.Close()) }() + err := mn.Dial(tests.Context(t)) + require.NoError(t, err) + tests.RequireLogMessage(t, observedLogs, "Best node switching is disabled") + }) + t.Run("Misconfigured lease check period won't start", func(t *testing.T) { + t.Parallel() + chainID := types.RandomID() + node := newHealthyNode(t, chainID) + lggr, observedLogs := logger.TestLoggerObserved(t, zap.InfoLevel) + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeHighestHead, + chainID: chainID, + logger: lggr, + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{node}, + leaseDuration: 0, + }) + defer func() { assert.NoError(t, mn.Close()) }() + err := mn.Dial(tests.Context(t)) + require.NoError(t, err) + tests.RequireLogMessage(t, observedLogs, "Best node switching is disabled") + }) + t.Run("Lease check updates active node", func(t *testing.T) { + t.Parallel() + chainID := types.RandomID() + node := newHealthyNode(t, chainID) + node.On("SubscribersCount").Return(int32(2)) + node.On("UnsubscribeAllExceptAliveLoop") + bestNode := newHealthyNode(t, chainID) + nodeSelector := newMockNodeSelector[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + nodeSelector.On("Select").Return(bestNode) + lggr, observedLogs := logger.TestLoggerObserved(t, zap.InfoLevel) + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeHighestHead, + chainID: chainID, + logger: lggr, + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{node, bestNode}, + leaseDuration: tests.TestInterval, + }) + defer func() { assert.NoError(t, mn.Close()) }() + mn.nodeSelector = nodeSelector + err := mn.Dial(tests.Context(t)) + require.NoError(t, err) + tests.AssertLogEventually(t, observedLogs, fmt.Sprintf("Switching to best node from %q to %q", node.String(), bestNode.String())) + tests.AssertEventually(t, func() bool { + mn.activeMu.RLock() + active := mn.activeNode + mn.activeMu.RUnlock() + return bestNode == active + }) + }) + t.Run("NodeStates returns proper states", func(t *testing.T) { + t.Parallel() + chainID := types.NewIDFromInt(10) + nodes := map[string]nodeState{ + "node_1": nodeStateAlive, + "node_2": nodeStateUnreachable, + "node_3": nodeStateDialed, + } + + opts := multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: chainID, + } + + expectedResult := map[string]string{} + for name, state := range nodes { + node := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + node.On("Name").Return(name).Once() + node.On("State").Return(state).Once() + opts.nodes = append(opts.nodes, node) + + sendOnly := newMockSendOnlyNode[types.ID, multiNodeRPCClient](t) + sendOnlyName := "send_only_" + name + sendOnly.On("Name").Return(sendOnlyName).Once() + sendOnly.On("State").Return(state).Once() + opts.sendonlys = append(opts.sendonlys, sendOnly) + + expectedResult[name] = state.String() + expectedResult[sendOnlyName] = state.String() + } + + mn := newTestMultiNode(t, opts) + states := mn.NodeStates() + assert.Equal(t, expectedResult, states) + }) +} + +func TestMultiNode_selectNode(t *testing.T) { + t.Parallel() + t.Run("Returns same node, if it's still healthy", func(t *testing.T) { + t.Parallel() + chainID := types.RandomID() + node1 := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + node1.On("State").Return(nodeStateAlive).Once() + node1.On("String").Return("node1").Maybe() + node2 := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + node2.On("String").Return("node2").Maybe() + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: chainID, + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{node1, node2}, + }) + nodeSelector := newMockNodeSelector[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + nodeSelector.On("Select").Return(node1).Once() + mn.nodeSelector = nodeSelector + prevActiveNode, err := mn.selectNode() + require.NoError(t, err) + require.Equal(t, node1.String(), prevActiveNode.String()) + newActiveNode, err := mn.selectNode() + require.NoError(t, err) + require.Equal(t, prevActiveNode.String(), newActiveNode.String()) + + }) + t.Run("Updates node if active is not healthy", func(t *testing.T) { + t.Parallel() + chainID := types.RandomID() + oldBest := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + oldBest.On("String").Return("oldBest").Maybe() + newBest := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + newBest.On("String").Return("newBest").Maybe() + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: chainID, + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{oldBest, newBest}, + }) + nodeSelector := newMockNodeSelector[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + nodeSelector.On("Select").Return(oldBest).Once() + mn.nodeSelector = nodeSelector + activeNode, err := mn.selectNode() + require.NoError(t, err) + require.Equal(t, oldBest.String(), activeNode.String()) + // old best died, so we should replace it + oldBest.On("State").Return(nodeStateOutOfSync).Twice() + nodeSelector.On("Select").Return(newBest).Once() + newActiveNode, err := mn.selectNode() + require.NoError(t, err) + require.Equal(t, newBest.String(), newActiveNode.String()) + + }) + t.Run("No active nodes - reports critical error", func(t *testing.T) { + t.Parallel() + chainID := types.RandomID() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.InfoLevel) + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: chainID, + logger: lggr, + }) + nodeSelector := newMockNodeSelector[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + nodeSelector.On("Select").Return(nil).Once() + nodeSelector.On("Name").Return("MockedNodeSelector").Once() + mn.nodeSelector = nodeSelector + node, err := mn.selectNode() + require.EqualError(t, err, ErroringNodeError.Error()) + require.Nil(t, node) + tests.RequireLogMessage(t, observedLogs, "No live RPC nodes available") + + }) +} + +func TestMultiNode_nLiveNodes(t *testing.T) { + t.Parallel() + type nodeParams struct { + BlockNumber int64 + TotalDifficulty *utils.Big + State nodeState + } + testCases := []struct { + Name string + ExpectedNLiveNodes int + ExpectedBlockNumber int64 + ExpectedTotalDifficulty *utils.Big + NodeParams []nodeParams + }{ + { + Name: "no nodes", + ExpectedTotalDifficulty: utils.NewBigI(0), + }, + { + Name: "Best node is not healthy", + ExpectedTotalDifficulty: utils.NewBigI(10), + ExpectedBlockNumber: 20, + ExpectedNLiveNodes: 3, + NodeParams: []nodeParams{ + { + State: nodeStateOutOfSync, + BlockNumber: 1000, + TotalDifficulty: utils.NewBigI(2000), + }, + { + State: nodeStateAlive, + BlockNumber: 20, + TotalDifficulty: utils.NewBigI(9), + }, + { + State: nodeStateAlive, + BlockNumber: 19, + TotalDifficulty: utils.NewBigI(10), + }, + { + State: nodeStateAlive, + BlockNumber: 11, + TotalDifficulty: nil, + }, + }, + }, + } + + chainID := types.RandomID() + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: chainID, + }) + for i := range testCases { + tc := testCases[i] + t.Run(tc.Name, func(t *testing.T) { + for _, params := range tc.NodeParams { + node := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + node.On("StateAndLatest").Return(params.State, params.BlockNumber, params.TotalDifficulty) + mn.nodes = append(mn.nodes, node) + } + + nNodes, blockNum, td := mn.nLiveNodes() + assert.Equal(t, tc.ExpectedNLiveNodes, nNodes) + assert.Equal(t, tc.ExpectedTotalDifficulty, td) + assert.Equal(t, tc.ExpectedBlockNumber, blockNum) + }) + } +} + +func TestMultiNode_BatchCallContextAll(t *testing.T) { + t.Parallel() + t.Run("Fails if failed to select active node", func(t *testing.T) { + chainID := types.RandomID() + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: chainID, + }) + nodeSelector := newMockNodeSelector[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + nodeSelector.On("Select").Return(nil).Once() + nodeSelector.On("Name").Return("MockedNodeSelector").Once() + mn.nodeSelector = nodeSelector + err := mn.BatchCallContextAll(tests.Context(t), nil) + require.EqualError(t, err, ErroringNodeError.Error()) + }) + t.Run("Returns error if RPC call fails for active node", func(t *testing.T) { + chainID := types.RandomID() + rpc := newMultiNodeRPCClient(t) + expectedError := errors.New("rpc failed to do the batch call") + rpc.On("BatchCallContext", mock.Anything, mock.Anything).Return(expectedError).Once() + node := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + node.On("RPC").Return(rpc) + nodeSelector := newMockNodeSelector[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + nodeSelector.On("Select").Return(node).Once() + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: chainID, + }) + mn.nodeSelector = nodeSelector + err := mn.BatchCallContextAll(tests.Context(t), nil) + require.EqualError(t, err, expectedError.Error()) + }) + t.Run("Waits for all nodes to complete the call and logs results", func(t *testing.T) { + // setup RPCs + failedRPC := newMultiNodeRPCClient(t) + failedRPC.On("BatchCallContext", mock.Anything, mock.Anything). + Return(errors.New("rpc failed to do the batch call")).Once() + okRPC := newMultiNodeRPCClient(t) + okRPC.On("BatchCallContext", mock.Anything, mock.Anything).Return(nil).Twice() + + // setup ok and failed auxiliary nodes + okNode := newMockSendOnlyNode[types.ID, multiNodeRPCClient](t) + okNode.On("RPC").Return(okRPC).Once() + failedNode := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + failedNode.On("RPC").Return(failedRPC).Once() + + // setup main node + mainNode := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + mainNode.On("RPC").Return(okRPC) + nodeSelector := newMockNodeSelector[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + nodeSelector.On("Select").Return(mainNode).Once() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: types.RandomID(), + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{failedNode, mainNode}, + sendonlys: []SendOnlyNode[types.ID, multiNodeRPCClient]{okNode}, + logger: lggr, + }) + mn.nodeSelector = nodeSelector + + err := mn.BatchCallContextAll(tests.Context(t), nil) + require.NoError(t, err) + tests.RequireLogMessage(t, observedLogs, "Secondary node BatchCallContext failed") + }) +} + +func TestMultiNode_SendTransaction(t *testing.T) { + t.Parallel() + t.Run("Fails if failed to select active node", func(t *testing.T) { + chainID := types.RandomID() + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: chainID, + }) + nodeSelector := newMockNodeSelector[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + nodeSelector.On("Select").Return(nil).Once() + nodeSelector.On("Name").Return("MockedNodeSelector").Once() + mn.nodeSelector = nodeSelector + err := mn.SendTransaction(tests.Context(t), nil) + require.EqualError(t, err, ErroringNodeError.Error()) + }) + t.Run("Returns error if RPC call fails for active node", func(t *testing.T) { + chainID := types.RandomID() + rpc := newMultiNodeRPCClient(t) + expectedError := errors.New("rpc failed to do the batch call") + rpc.On("SendTransaction", mock.Anything, mock.Anything).Return(expectedError).Once() + node := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + node.On("RPC").Return(rpc) + nodeSelector := newMockNodeSelector[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + nodeSelector.On("Select").Return(node).Once() + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: chainID, + }) + mn.nodeSelector = nodeSelector + err := mn.SendTransaction(tests.Context(t), nil) + require.EqualError(t, err, expectedError.Error()) + }) + t.Run("Returns result of main node and logs secondary nodes results", func(t *testing.T) { + // setup RPCs + failedRPC := newMultiNodeRPCClient(t) + failedRPC.On("SendTransaction", mock.Anything, mock.Anything). + Return(errors.New("rpc failed to do the batch call")).Once() + okRPC := newMultiNodeRPCClient(t) + okRPC.On("SendTransaction", mock.Anything, mock.Anything).Return(nil).Twice() + + // setup ok and failed auxiliary nodes + okNode := newMockSendOnlyNode[types.ID, multiNodeRPCClient](t) + okNode.On("RPC").Return(okRPC).Once() + okNode.On("String").Return("okNode") + failedNode := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + failedNode.On("RPC").Return(failedRPC).Once() + failedNode.On("String").Return("failedNode") + + // setup main node + mainNode := newMockNode[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + mainNode.On("RPC").Return(okRPC) + nodeSelector := newMockNodeSelector[types.ID, types.Head[Hashable], multiNodeRPCClient](t) + nodeSelector.On("Select").Return(mainNode).Once() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + mn := newTestMultiNode(t, multiNodeOpts{ + selectionMode: NodeSelectionModeRoundRobin, + chainID: types.RandomID(), + nodes: []Node[types.ID, types.Head[Hashable], multiNodeRPCClient]{failedNode, mainNode}, + sendonlys: []SendOnlyNode[types.ID, multiNodeRPCClient]{okNode}, + logger: lggr, + sendOnlyErrorParser: func(err error) SendTxReturnCode { + if err != nil { + return Fatal + } + + return Successful + }, + }) + mn.nodeSelector = nodeSelector + + err := mn.SendTransaction(tests.Context(t), nil) + require.NoError(t, err) + tests.AssertLogEventually(t, observedLogs, "Sendonly node sent transaction") + tests.AssertLogEventually(t, observedLogs, "RPC returned error") + }) +} diff --git a/common/client/node.go b/common/client/node.go index 20d098e03f7..f28a171a558 100644 --- a/common/client/node.go +++ b/common/client/node.go @@ -44,6 +44,7 @@ type NodeConfig interface { SyncThreshold() uint32 } +//go:generate mockery --quiet --name Node --structname mockNode --filename "mock_node_test.go" --inpackage --case=underscore type Node[ CHAIN_ID types.ID, HEAD Head, @@ -177,19 +178,21 @@ func (n *node[CHAIN_ID, HEAD, RPC]) UnsubscribeAllExceptAliveLoop() { } func (n *node[CHAIN_ID, HEAD, RPC]) Close() error { - return n.StopOnce(n.name, func() error { - defer func() { - n.wg.Wait() - n.rpc.Close() - }() + return n.StopOnce(n.name, n.close) +} - n.stateMu.Lock() - defer n.stateMu.Unlock() +func (n *node[CHAIN_ID, HEAD, RPC]) close() error { + defer func() { + n.wg.Wait() + n.rpc.Close() + }() - n.cancelNodeCtx() - n.state = nodeStateClosed - return nil - }) + n.stateMu.Lock() + defer n.stateMu.Unlock() + + n.cancelNodeCtx() + n.state = nodeStateClosed + return nil } // Start dials and verifies the node diff --git a/common/client/node_fsm_test.go b/common/client/node_fsm_test.go new file mode 100644 index 00000000000..87e90846699 --- /dev/null +++ b/common/client/node_fsm_test.go @@ -0,0 +1,108 @@ +package client + +import ( + "slices" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/smartcontractkit/chainlink/v2/common/types" +) + +type fnMock struct{ calls int } + +func (fm *fnMock) Fn() { + fm.calls++ +} + +func (fm *fnMock) AssertNotCalled(t *testing.T) { + assert.Equal(t, 0, fm.calls) +} + +func (fm *fnMock) AssertCalled(t *testing.T) { + assert.Greater(t, fm.calls, 0) +} + +func newTestTransitionNode(t *testing.T, rpc *mockNodeClient[types.ID, Head]) testNode { + return newTestNode(t, testNodeOpts{rpc: rpc}) +} + +func TestUnit_Node_StateTransitions(t *testing.T) { + t.Parallel() + + t.Run("setState", func(t *testing.T) { + n := newTestTransitionNode(t, nil) + assert.Equal(t, nodeStateUndialed, n.State()) + n.setState(nodeStateAlive) + assert.Equal(t, nodeStateAlive, n.State()) + n.setState(nodeStateUndialed) + assert.Equal(t, nodeStateUndialed, n.State()) + }) + + t.Run("transitionToAlive", func(t *testing.T) { + const destinationState = nodeStateAlive + allowedStates := []nodeState{nodeStateDialed, nodeStateInvalidChainID} + rpc := newMockNodeClient[types.ID, Head](t) + testTransition(t, rpc, testNode.transitionToAlive, destinationState, allowedStates...) + }) + + t.Run("transitionToInSync", func(t *testing.T) { + const destinationState = nodeStateAlive + allowedStates := []nodeState{nodeStateOutOfSync} + rpc := newMockNodeClient[types.ID, Head](t) + testTransition(t, rpc, testNode.transitionToInSync, destinationState, allowedStates...) + }) + t.Run("transitionToOutOfSync", func(t *testing.T) { + const destinationState = nodeStateOutOfSync + allowedStates := []nodeState{nodeStateAlive} + rpc := newMockNodeClient[types.ID, Head](t) + rpc.On("DisconnectAll").Once() + testTransition(t, rpc, testNode.transitionToOutOfSync, destinationState, allowedStates...) + }) + t.Run("transitionToUnreachable", func(t *testing.T) { + const destinationState = nodeStateUnreachable + allowedStates := []nodeState{nodeStateUndialed, nodeStateDialed, nodeStateAlive, nodeStateOutOfSync, nodeStateInvalidChainID} + rpc := newMockNodeClient[types.ID, Head](t) + rpc.On("DisconnectAll").Times(len(allowedStates)) + testTransition(t, rpc, testNode.transitionToUnreachable, destinationState, allowedStates...) + }) + t.Run("transitionToInvalidChain", func(t *testing.T) { + const destinationState = nodeStateInvalidChainID + allowedStates := []nodeState{nodeStateDialed, nodeStateOutOfSync} + rpc := newMockNodeClient[types.ID, Head](t) + rpc.On("DisconnectAll").Times(len(allowedStates)) + testTransition(t, rpc, testNode.transitionToInvalidChainID, destinationState, allowedStates...) + }) +} + +func testTransition(t *testing.T, rpc *mockNodeClient[types.ID, Head], transition func(node testNode, fn func()), destinationState nodeState, allowedStates ...nodeState) { + node := newTestTransitionNode(t, rpc) + for _, allowedState := range allowedStates { + m := new(fnMock) + node.setState(allowedState) + transition(node, m.Fn) + assert.Equal(t, destinationState, node.State(), "Expected node to successfully transition from %s to %s state", allowedState, destinationState) + m.AssertCalled(t) + } + // noop on attempt to transition from Closed state + m := new(fnMock) + node.setState(nodeStateClosed) + transition(node, m.Fn) + m.AssertNotCalled(t) + assert.Equal(t, nodeStateClosed, node.State(), "Expected node to remain in closed state on transition attempt") + + for _, nodeState := range allNodeStates { + if slices.Contains(allowedStates, nodeState) || nodeState == nodeStateClosed { + continue + } + + m := new(fnMock) + node.setState(nodeState) + assert.Panics(t, func() { + transition(node, m.Fn) + }, "Expected transition from `%s` to `%s` to panic", nodeState, destinationState) + m.AssertNotCalled(t) + assert.Equal(t, nodeState, node.State(), "Expected node to remain in initial state on invalid transition") + + } +} diff --git a/common/client/node_lifecycle.go b/common/client/node_lifecycle.go index 149c5f01a6d..4193560e296 100644 --- a/common/client/node_lifecycle.go +++ b/common/client/node_lifecycle.go @@ -60,6 +60,8 @@ const ( msgDegradedState = "Chainlink is now operating in a degraded state and urgent action is required to resolve the issue" ) +const rpcSubscriptionMethodNewHeads = "newHeads" + // Node is a FSM // Each state has a loop that goes with it, which monitors the node and moves it into another state as necessary. // Only one loop must run at a time. @@ -90,12 +92,14 @@ func (n *node[CHAIN_ID, HEAD, RPC]) aliveLoop() { lggr.Tracew("Alive loop starting", "nodeState", n.State()) headsC := make(chan HEAD) - sub, err := n.rpc.Subscribe(n.nodeCtx, headsC, "newHeads") + sub, err := n.rpc.Subscribe(n.nodeCtx, headsC, rpcSubscriptionMethodNewHeads) if err != nil { lggr.Errorw("Initial subscribe for heads failed", "nodeState", n.State()) n.declareUnreachable() return } + // TODO: nit fix. If multinode switches primary node before we set sub as AliveSub, sub will be closed and we'll + // falsely transition this node to unreachable state n.rpc.SetAliveLoopSub(sub) defer sub.Unsubscribe() @@ -289,7 +293,7 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td lggr.Tracew("Successfully subscribed to heads feed on out-of-sync RPC node", "nodeState", n.State()) ch := make(chan HEAD) - sub, err := n.rpc.Subscribe(n.nodeCtx, ch, "newHeads") + sub, err := n.rpc.Subscribe(n.nodeCtx, ch, rpcSubscriptionMethodNewHeads) if err != nil { lggr.Errorw("Failed to subscribe heads on out-of-sync RPC node", "nodeState", n.State(), "err", err) n.declareUnreachable() @@ -310,11 +314,11 @@ func (n *node[CHAIN_ID, HEAD, RPC]) outOfSyncLoop(isOutOfSync func(num int64, td n.setLatestReceived(head.BlockNumber(), head.BlockDifficulty()) if !isOutOfSync(head.BlockNumber(), head.BlockDifficulty()) { // back in-sync! flip back into alive loop - lggr.Infow(fmt.Sprintf("%s: %s. Node was out-of-sync for %s", msgInSync, n.String(), time.Since(outOfSyncAt)), "blockNumber", head.BlockNumber(), "totalDifficulty", "nodeState", n.State()) + lggr.Infow(fmt.Sprintf("%s: %s. Node was out-of-sync for %s", msgInSync, n.String(), time.Since(outOfSyncAt)), "blockNumber", head.BlockNumber(), "blockDifficulty", head.BlockDifficulty(), "nodeState", n.State()) n.declareInSync() return } - lggr.Debugw(msgReceivedBlock, "blockNumber", head.BlockNumber(), "totalDifficulty", "nodeState", n.State()) + lggr.Debugw(msgReceivedBlock, "blockNumber", head.BlockNumber(), "blockDifficulty", head.BlockDifficulty(), "nodeState", n.State()) case <-time.After(zombieNodeCheckInterval(n.noNewHeadsThreshold)): if n.nLiveNodes != nil { if l, _, _ := n.nLiveNodes(); l < 1 { diff --git a/common/client/node_lifecycle_test.go b/common/client/node_lifecycle_test.go new file mode 100644 index 00000000000..564c08bbdcc --- /dev/null +++ b/common/client/node_lifecycle_test.go @@ -0,0 +1,1070 @@ +package client + +import ( + "fmt" + "sync/atomic" + "testing" + + "github.com/cometbft/cometbft/libs/rand" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "go.uber.org/zap" + + "github.com/smartcontractkit/chainlink-relay/pkg/utils/tests" + + "github.com/smartcontractkit/chainlink/v2/common/types" + "github.com/smartcontractkit/chainlink/v2/common/types/mocks" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/utils" +) + +func TestUnit_NodeLifecycle_aliveLoop(t *testing.T) { + t.Parallel() + + newDialedNode := func(t *testing.T, opts testNodeOpts) testNode { + node := newTestNode(t, opts) + opts.rpc.On("Close").Return(nil).Once() + + node.setState(nodeStateDialed) + return node + } + + t.Run("returns on closed", func(t *testing.T) { + node := newTestNode(t, testNodeOpts{}) + node.setState(nodeStateClosed) + node.wg.Add(1) + node.aliveLoop() + + }) + t.Run("if initial subscribe fails, transitions to unreachable", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + node := newDialedNode(t, testNodeOpts{ + rpc: rpc, + }) + defer func() { assert.NoError(t, node.close()) }() + + expectedError := errors.New("failed to subscribe to rpc") + rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(nil, expectedError).Once() + rpc.On("DisconnectAll").Once() + // might be called in unreachable loop + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe() + node.declareAlive() + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateUnreachable + }) + + }) + t.Run("if remote RPC connection is closed transitions to unreachable", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + + lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + node := newDialedNode(t, testNodeOpts{ + rpc: rpc, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + + sub := mocks.NewSubscription(t) + errChan := make(chan error) + close(errChan) + sub.On("Err").Return((<-chan error)(errChan)).Once() + sub.On("Unsubscribe").Once() + rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(sub, nil).Once() + rpc.On("SetAliveLoopSub", sub).Once() + // disconnects all on transfer to unreachable + rpc.On("DisconnectAll").Once() + // might be called in unreachable loop + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe() + node.declareAlive() + tests.AssertLogEventually(t, observedLogs, "Subscription was terminated") + assert.Equal(t, nodeStateUnreachable, node.State()) + }) + + newSubscribedNode := func(t *testing.T, opts testNodeOpts) testNode { + sub := mocks.NewSubscription(t) + sub.On("Err").Return((<-chan error)(nil)) + sub.On("Unsubscribe").Once() + opts.rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(sub, nil).Once() + opts.rpc.On("SetAliveLoopSub", sub).Once() + return newDialedNode(t, opts) + } + t.Run("Stays alive and waits for signal", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + node := newSubscribedNode(t, testNodeOpts{ + config: testNodeConfig{}, + rpc: rpc, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + node.declareAlive() + tests.AssertLogEventually(t, observedLogs, "Head liveness checking disabled") + tests.AssertLogEventually(t, observedLogs, "Polling disabled") + assert.Equal(t, nodeStateAlive, node.State()) + }) + t.Run("stays alive while below pollFailureThreshold and resets counter on success", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + const pollFailureThreshold = 3 + node := newSubscribedNode(t, testNodeOpts{ + config: testNodeConfig{ + pollFailureThreshold: pollFailureThreshold, + pollInterval: tests.TestInterval, + }, + rpc: rpc, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + + pollError := errors.New("failed to get ClientVersion") + // 1. Return error several times, but below threshold + rpc.On("ClientVersion", mock.Anything).Return("", pollError).Run(func(_ mock.Arguments) { + // stays healthy while below threshold + assert.Equal(t, nodeStateAlive, node.State()) + }).Times(pollFailureThreshold - 1) + // 2. Successful call that is expected to reset counter + rpc.On("ClientVersion", mock.Anything).Return("client_version", nil).Once() + // 3. Return error. If we have not reset the timer, we'll transition to nonAliveState + rpc.On("ClientVersion", mock.Anything).Return("", pollError).Once() + // 4. Once during the call, check if node is alive + var ensuredAlive atomic.Bool + rpc.On("ClientVersion", mock.Anything).Return("client_version", nil).Run(func(_ mock.Arguments) { + if ensuredAlive.Load() { + return + } + ensuredAlive.Store(true) + assert.Equal(t, nodeStateAlive, node.State()) + }).Once() + // redundant call to stay in alive state + rpc.On("ClientVersion", mock.Anything).Return("client_version", nil) + node.declareAlive() + tests.AssertLogCountEventually(t, observedLogs, fmt.Sprintf("Poll failure, RPC endpoint %s failed to respond properly", node.String()), pollFailureThreshold) + tests.AssertLogCountEventually(t, observedLogs, "Version poll successful", 2) + assert.True(t, ensuredAlive.Load(), "expected to ensure that node was alive") + + }) + t.Run("with threshold poll failures, transitions to unreachable", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + const pollFailureThreshold = 3 + node := newSubscribedNode(t, testNodeOpts{ + config: testNodeConfig{ + pollFailureThreshold: pollFailureThreshold, + pollInterval: tests.TestInterval, + }, + rpc: rpc, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + pollError := errors.New("failed to get ClientVersion") + rpc.On("ClientVersion", mock.Anything).Return("", pollError) + // disconnects all on transfer to unreachable + rpc.On("DisconnectAll").Once() + // might be called in unreachable loop + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe() + node.declareAlive() + tests.AssertLogCountEventually(t, observedLogs, fmt.Sprintf("Poll failure, RPC endpoint %s failed to respond properly", node.String()), pollFailureThreshold) + tests.AssertEventually(t, func() bool { + return nodeStateUnreachable == node.State() + }) + }) + t.Run("with threshold poll failures, but we are the last node alive, forcibly keeps it alive", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + const pollFailureThreshold = 3 + node := newSubscribedNode(t, testNodeOpts{ + config: testNodeConfig{ + pollFailureThreshold: pollFailureThreshold, + pollInterval: tests.TestInterval, + }, + rpc: rpc, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *utils.Big) { + return 1, 20, utils.NewBigI(10) + } + pollError := errors.New("failed to get ClientVersion") + rpc.On("ClientVersion", mock.Anything).Return("", pollError) + node.declareAlive() + tests.AssertLogEventually(t, observedLogs, fmt.Sprintf("RPC endpoint failed to respond to %d consecutive polls", pollFailureThreshold)) + assert.Equal(t, nodeStateAlive, node.State()) + }) + t.Run("when behind more than SyncThreshold, transitions to out of sync", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + const syncThreshold = 10 + node := newSubscribedNode(t, testNodeOpts{ + config: testNodeConfig{ + pollInterval: tests.TestInterval, + syncThreshold: syncThreshold, + selectionMode: NodeSelectionModeRoundRobin, + }, + rpc: rpc, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + node.stateLatestBlockNumber = 20 + node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *utils.Big) { + return 10, syncThreshold + node.stateLatestBlockNumber + 1, utils.NewBigI(10) + } + rpc.On("ClientVersion", mock.Anything).Return("", nil) + // tries to redial in outOfSync + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Run(func(_ mock.Arguments) { + assert.Equal(t, nodeStateOutOfSync, node.State()) + }).Once() + // disconnects all on transfer to unreachable or outOfSync + rpc.On("DisconnectAll").Maybe() + // might be called in unreachable loop + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe() + node.declareAlive() + tests.AssertLogEventually(t, observedLogs, "Failed to dial out-of-sync RPC node") + }) + t.Run("when behind more than SyncThreshold but we are the last live node, forcibly stays alive", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + const syncThreshold = 10 + node := newSubscribedNode(t, testNodeOpts{ + config: testNodeConfig{ + pollInterval: tests.TestInterval, + syncThreshold: syncThreshold, + selectionMode: NodeSelectionModeRoundRobin, + }, + rpc: rpc, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + node.stateLatestBlockNumber = 20 + node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *utils.Big) { + return 1, syncThreshold + node.stateLatestBlockNumber + 1, utils.NewBigI(10) + } + rpc.On("ClientVersion", mock.Anything).Return("", nil) + node.declareAlive() + tests.AssertLogEventually(t, observedLogs, fmt.Sprintf("RPC endpoint has fallen behind; %s %s", msgCannotDisable, msgDegradedState)) + }) + t.Run("when behind but SyncThreshold=0, stay alive", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + node := newSubscribedNode(t, testNodeOpts{ + config: testNodeConfig{ + pollInterval: tests.TestInterval, + syncThreshold: 0, + selectionMode: NodeSelectionModeRoundRobin, + }, + rpc: rpc, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + node.stateLatestBlockNumber = 20 + node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *utils.Big) { + return 1, node.stateLatestBlockNumber + 100, utils.NewBigI(10) + } + rpc.On("ClientVersion", mock.Anything).Return("", nil) + node.declareAlive() + tests.AssertLogCountEventually(t, observedLogs, "Version poll successful", 2) + assert.Equal(t, nodeStateAlive, node.State()) + }) + + t.Run("when no new heads received for threshold, transitions to out of sync", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + node := newSubscribedNode(t, testNodeOpts{ + config: testNodeConfig{}, + noNewHeadsThreshold: tests.TestInterval, + rpc: rpc, + }) + defer func() { assert.NoError(t, node.close()) }() + // tries to redial in outOfSync + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Run(func(_ mock.Arguments) { + assert.Equal(t, nodeStateOutOfSync, node.State()) + }).Once() + // disconnects all on transfer to unreachable or outOfSync + rpc.On("DisconnectAll").Maybe() + // might be called in unreachable loop + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe() + node.declareAlive() + tests.AssertEventually(t, func() bool { + // right after outOfSync we'll transfer to unreachable due to returned error on Dial + // we check that we were in out of sync state on first Dial call + return node.State() == nodeStateUnreachable + }) + }) + t.Run("when no new heads received for threshold but we are the last live node, forcibly stays alive", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + node := newSubscribedNode(t, testNodeOpts{ + config: testNodeConfig{}, + lggr: lggr, + noNewHeadsThreshold: tests.TestInterval, + rpc: rpc, + }) + defer func() { assert.NoError(t, node.close()) }() + node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *utils.Big) { + return 1, 20, utils.NewBigI(10) + } + node.declareAlive() + tests.AssertLogEventually(t, observedLogs, fmt.Sprintf("RPC endpoint detected out of sync; %s %s", msgCannotDisable, msgDegradedState)) + assert.Equal(t, nodeStateAlive, node.State()) + }) + + t.Run("rpc closed head channel", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + sub := mocks.NewSubscription(t) + sub.On("Err").Return((<-chan error)(nil)) + sub.On("Unsubscribe").Once() + rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Run(func(args mock.Arguments) { + ch := args.Get(1).(chan<- Head) + close(ch) + }).Return(sub, nil).Once() + rpc.On("SetAliveLoopSub", sub).Once() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.ErrorLevel) + node := newDialedNode(t, testNodeOpts{ + lggr: lggr, + config: testNodeConfig{}, + noNewHeadsThreshold: tests.TestInterval, + rpc: rpc, + }) + defer func() { assert.NoError(t, node.close()) }() + // disconnects all on transfer to unreachable or outOfSync + rpc.On("DisconnectAll").Once() + // might be called in unreachable loop + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe() + node.declareAlive() + tests.AssertLogEventually(t, observedLogs, "Subscription channel unexpectedly closed") + assert.Equal(t, nodeStateUnreachable, node.State()) + + }) + t.Run("updates block number and difficulty on new head", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + sub := mocks.NewSubscription(t) + sub.On("Err").Return((<-chan error)(nil)) + sub.On("Unsubscribe").Once() + expectedBlockNumber := rand.Int64() + expectedDiff := utils.NewBigI(rand.Int64()) + rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Run(func(args mock.Arguments) { + ch := args.Get(1).(chan<- Head) + go writeHeads(t, ch, head{BlockNumber: expectedBlockNumber, BlockDifficulty: expectedDiff}) + }).Return(sub, nil).Once() + rpc.On("SetAliveLoopSub", sub).Once() + node := newDialedNode(t, testNodeOpts{ + config: testNodeConfig{}, + rpc: rpc, + }) + defer func() { assert.NoError(t, node.close()) }() + node.declareAlive() + tests.AssertEventually(t, func() bool { + state, block, diff := node.StateAndLatest() + return state == nodeStateAlive && block == expectedBlockNumber == diff.Equal(expectedDiff) + }) + }) +} + +type head struct { + BlockNumber int64 + BlockDifficulty *utils.Big +} + +func writeHeads(t *testing.T, ch chan<- Head, heads ...head) { + for _, head := range heads { + h := newMockHead(t) + h.On("BlockNumber").Return(head.BlockNumber) + h.On("BlockDifficulty").Return(head.BlockDifficulty) + select { + case ch <- h: + case <-tests.Context(t).Done(): + return + } + } +} + +func setupRPCForAliveLoop(t *testing.T, rpc *mockNodeClient[types.ID, Head]) { + rpc.On("Dial", mock.Anything).Return(nil).Maybe() + aliveSubscription := mocks.NewSubscription(t) + aliveSubscription.On("Err").Return((<-chan error)(nil)).Maybe() + aliveSubscription.On("Unsubscribe").Maybe() + rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(aliveSubscription, nil).Maybe() + rpc.On("SetAliveLoopSub", mock.Anything).Maybe() +} + +func TestUnit_NodeLifecycle_outOfSyncLoop(t *testing.T) { + t.Parallel() + + newAliveNode := func(t *testing.T, opts testNodeOpts) testNode { + node := newTestNode(t, opts) + opts.rpc.On("Close").Return(nil).Once() + // disconnects all on transfer to unreachable or outOfSync + opts.rpc.On("DisconnectAll") + node.setState(nodeStateAlive) + return node + } + + stubIsOutOfSync := func(num int64, td *utils.Big) bool { + return false + } + + t.Run("returns on closed", func(t *testing.T) { + t.Parallel() + node := newTestNode(t, testNodeOpts{}) + node.setState(nodeStateClosed) + node.wg.Add(1) + node.outOfSyncLoop(stubIsOutOfSync) + }) + t.Run("on old blocks stays outOfSync and returns on close", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil).Once() + // might be called multiple times + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() + + outOfSyncSubscription := mocks.NewSubscription(t) + outOfSyncSubscription.On("Err").Return((<-chan error)(nil)) + outOfSyncSubscription.On("Unsubscribe").Once() + heads := []head{{BlockNumber: 7}, {BlockNumber: 11}, {BlockNumber: 13}} + rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Run(func(args mock.Arguments) { + ch := args.Get(1).(chan<- Head) + go writeHeads(t, ch, heads...) + }).Return(outOfSyncSubscription, nil).Once() + rpc.On("Dial", mock.Anything).Return(errors.New("failed to redial")).Maybe() + + node.declareOutOfSync(func(num int64, td *utils.Big) bool { + return true + }) + tests.AssertLogCountEventually(t, observedLogs, msgReceivedBlock, len(heads)) + assert.Equal(t, nodeStateOutOfSync, node.State()) + }) + t.Run("if initial dial fails, transitions to unreachable", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + }) + defer func() { assert.NoError(t, node.close()) }() + + expectedError := errors.New("failed to dial rpc") + // might be called again in unreachable loop, so no need to set once + rpc.On("Dial", mock.Anything).Return(expectedError) + node.declareOutOfSync(stubIsOutOfSync) + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateUnreachable + }) + }) + t.Run("if fail to get chainID, transitions to invalidChainID", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil).Once() + expectedError := errors.New("failed to get chain ID") + // might be called multiple times + rpc.On("ChainID", mock.Anything).Return(types.NewIDFromInt(0), expectedError) + node.declareOutOfSync(stubIsOutOfSync) + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateInvalidChainID + }) + }) + t.Run("if chainID does not match, transitions to invalidChainID", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.NewIDFromInt(10) + rpcChainID := types.NewIDFromInt(11) + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil).Once() + // might be called multiple times + rpc.On("ChainID", mock.Anything).Return(rpcChainID, nil) + node.declareOutOfSync(stubIsOutOfSync) + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateInvalidChainID + }) + }) + t.Run("if fails to subscribe, becomes unreachable", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil).Once() + // might be called multiple times + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() + expectedError := errors.New("failed to subscribe") + rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(nil, expectedError) + rpc.On("Dial", mock.Anything).Return(errors.New("failed to redial")).Maybe() + node.declareOutOfSync(stubIsOutOfSync) + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateUnreachable + }) + }) + t.Run("on subscription termination becomes unreachable", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.ErrorLevel) + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil).Once() + // might be called multiple times + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() + + sub := mocks.NewSubscription(t) + errChan := make(chan error, 1) + errChan <- errors.New("subscription was terminate") + sub.On("Err").Return((<-chan error)(errChan)) + sub.On("Unsubscribe").Once() + rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(sub, nil).Once() + rpc.On("Dial", mock.Anything).Return(errors.New("failed to redial")).Maybe() + node.declareOutOfSync(stubIsOutOfSync) + tests.AssertLogEventually(t, observedLogs, "Subscription was terminated") + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateUnreachable + }) + }) + t.Run("becomes unreachable if head channel is closed", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.ErrorLevel) + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil).Once() + // might be called multiple times + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() + + sub := mocks.NewSubscription(t) + sub.On("Err").Return((<-chan error)(nil)) + sub.On("Unsubscribe").Once() + rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Run(func(args mock.Arguments) { + ch := args.Get(1).(chan<- Head) + close(ch) + }).Return(sub, nil).Once() + rpc.On("Dial", mock.Anything).Return(errors.New("failed to redial")).Maybe() + node.declareOutOfSync(stubIsOutOfSync) + tests.AssertLogEventually(t, observedLogs, "Subscription channel unexpectedly closed") + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateUnreachable + }) + }) + + t.Run("becomes alive if it receives a newer head", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil).Once() + // might be called multiple times + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() + + outOfSyncSubscription := mocks.NewSubscription(t) + outOfSyncSubscription.On("Err").Return((<-chan error)(nil)) + outOfSyncSubscription.On("Unsubscribe").Once() + const highestBlock = 1000 + rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Run(func(args mock.Arguments) { + ch := args.Get(1).(chan<- Head) + go writeHeads(t, ch, head{BlockNumber: highestBlock - 1}, head{BlockNumber: highestBlock}) + }).Return(outOfSyncSubscription, nil).Once() + + setupRPCForAliveLoop(t, rpc) + + node.declareOutOfSync(func(num int64, td *utils.Big) bool { + return num < highestBlock + }) + tests.AssertLogEventually(t, observedLogs, msgReceivedBlock) + tests.AssertLogEventually(t, observedLogs, msgInSync) + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateAlive + }) + }) + t.Run("becomes alive if there is no other nodes", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + node := newAliveNode(t, testNodeOpts{ + noNewHeadsThreshold: tests.TestInterval, + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *utils.Big) { + return 0, 100, utils.NewBigI(200) + } + + rpc.On("Dial", mock.Anything).Return(nil).Once() + // might be called multiple times + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil).Once() + + outOfSyncSubscription := mocks.NewSubscription(t) + outOfSyncSubscription.On("Err").Return((<-chan error)(nil)) + outOfSyncSubscription.On("Unsubscribe").Once() + rpc.On("Subscribe", mock.Anything, mock.Anything, rpcSubscriptionMethodNewHeads).Return(outOfSyncSubscription, nil).Once() + + setupRPCForAliveLoop(t, rpc) + + node.declareOutOfSync(stubIsOutOfSync) + tests.AssertLogEventually(t, observedLogs, "RPC endpoint is still out of sync, but there are no other available nodes. This RPC node will be forcibly moved back into the live pool in a degraded state") + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateAlive + }) + }) +} + +func TestUnit_NodeLifecycle_unreachableLoop(t *testing.T) { + t.Parallel() + + newAliveNode := func(t *testing.T, opts testNodeOpts) testNode { + node := newTestNode(t, opts) + opts.rpc.On("Close").Return(nil).Once() + // disconnects all on transfer to unreachable + opts.rpc.On("DisconnectAll") + + node.setState(nodeStateAlive) + return node + } + t.Run("returns on closed", func(t *testing.T) { + t.Parallel() + node := newTestNode(t, testNodeOpts{}) + node.setState(nodeStateClosed) + node.wg.Add(1) + node.unreachableLoop() + + }) + t.Run("on failed redial, keeps trying", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")) + node.declareUnreachable() + tests.AssertLogCountEventually(t, observedLogs, "Failed to redial RPC node; still unreachable", 2) + }) + t.Run("on failed chainID verification, keep trying", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil) + rpc.On("ChainID", mock.Anything).Run(func(_ mock.Arguments) { + assert.Equal(t, nodeStateDialed, node.State()) + }).Return(nodeChainID, errors.New("failed to get chain id")) + node.declareUnreachable() + tests.AssertLogCountEventually(t, observedLogs, "Failed to redial RPC node; verify failed", 2) + }) + t.Run("on chain ID mismatch transitions to invalidChainID", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.NewIDFromInt(10) + rpcChainID := types.NewIDFromInt(11) + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil) + rpc.On("ChainID", mock.Anything).Return(rpcChainID, nil) + node.declareUnreachable() + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateInvalidChainID + }) + }) + t.Run("on valid chain ID becomes alive", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + node := newAliveNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil) + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil) + + setupRPCForAliveLoop(t, rpc) + + node.declareUnreachable() + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateAlive + }) + }) +} + +func TestUnit_NodeLifecycle_invalidChainIDLoop(t *testing.T) { + t.Parallel() + newDialedNode := func(t *testing.T, opts testNodeOpts) testNode { + node := newTestNode(t, opts) + opts.rpc.On("Close").Return(nil).Once() + opts.rpc.On("DisconnectAll") + + node.setState(nodeStateDialed) + return node + } + t.Run("returns on closed", func(t *testing.T) { + t.Parallel() + node := newTestNode(t, testNodeOpts{}) + node.setState(nodeStateClosed) + node.wg.Add(1) + node.invalidChainIDLoop() + + }) + t.Run("on failed chainID call becomes unreachable", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + node := newDialedNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("ChainID", mock.Anything).Return(nodeChainID, errors.New("failed to get chain id")) + // for unreachable loop + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")).Maybe() + node.declareInvalidChainID() + tests.AssertLogEventually(t, observedLogs, "Unexpected error while verifying RPC node chain ID") + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateUnreachable + }) + }) + t.Run("on chainID mismatch keeps trying", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.NewIDFromInt(10) + rpcChainID := types.NewIDFromInt(11) + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + node := newDialedNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("ChainID", mock.Anything).Return(rpcChainID, nil) + node.declareInvalidChainID() + tests.AssertLogCountEventually(t, observedLogs, "Failed to verify RPC node; remote endpoint returned the wrong chain ID", 2) + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateInvalidChainID + }) + }) + t.Run("on valid chainID becomes alive", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + node := newDialedNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil) + + setupRPCForAliveLoop(t, rpc) + + node.declareInvalidChainID() + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateAlive + }) + }) +} + +func TestUnit_NodeLifecycle_start(t *testing.T) { + t.Parallel() + + newNode := func(t *testing.T, opts testNodeOpts) testNode { + node := newTestNode(t, opts) + opts.rpc.On("Close").Return(nil).Once() + + return node + } + t.Run("if fails on initial dial, becomes unreachable", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + node := newNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(errors.New("failed to dial")) + // disconnects all on transfer to unreachable + rpc.On("DisconnectAll") + err := node.Start(tests.Context(t)) + assert.NoError(t, err) + tests.AssertLogEventually(t, observedLogs, "Dial failed: Node is unreachable") + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateUnreachable + }) + }) + t.Run("if chainID verification fails, becomes unreachable", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.DebugLevel) + node := newNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + lggr: lggr, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil) + rpc.On("ChainID", mock.Anything).Run(func(_ mock.Arguments) { + assert.Equal(t, nodeStateDialed, node.State()) + }).Return(nodeChainID, errors.New("failed to get chain id")) + // disconnects all on transfer to unreachable + rpc.On("DisconnectAll") + err := node.Start(tests.Context(t)) + assert.NoError(t, err) + tests.AssertLogEventually(t, observedLogs, "Verify failed") + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateUnreachable + }) + }) + t.Run("on chain ID mismatch transitions to invalidChainID", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.NewIDFromInt(10) + rpcChainID := types.NewIDFromInt(11) + node := newNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil) + rpc.On("ChainID", mock.Anything).Return(rpcChainID, nil) + // disconnects all on transfer to unreachable + rpc.On("DisconnectAll") + err := node.Start(tests.Context(t)) + assert.NoError(t, err) + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateInvalidChainID + }) + }) + t.Run("on valid chain ID becomes alive", func(t *testing.T) { + t.Parallel() + rpc := newMockNodeClient[types.ID, Head](t) + nodeChainID := types.RandomID() + node := newNode(t, testNodeOpts{ + rpc: rpc, + chainID: nodeChainID, + }) + defer func() { assert.NoError(t, node.close()) }() + + rpc.On("Dial", mock.Anything).Return(nil) + rpc.On("ChainID", mock.Anything).Return(nodeChainID, nil) + + setupRPCForAliveLoop(t, rpc) + + err := node.Start(tests.Context(t)) + assert.NoError(t, err) + tests.AssertEventually(t, func() bool { + return node.State() == nodeStateAlive + }) + }) +} + +func TestUnit_NodeLifecycle_syncStatus(t *testing.T) { + t.Parallel() + t.Run("skip if nLiveNodes is not configured", func(t *testing.T) { + node := newTestNode(t, testNodeOpts{}) + outOfSync, liveNodes := node.syncStatus(0, nil) + assert.Equal(t, false, outOfSync) + assert.Equal(t, 0, liveNodes) + }) + t.Run("skip if syncThreshold is not configured", func(t *testing.T) { + node := newTestNode(t, testNodeOpts{}) + node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *utils.Big) { + return + } + outOfSync, liveNodes := node.syncStatus(0, nil) + assert.Equal(t, false, outOfSync) + assert.Equal(t, 0, liveNodes) + }) + t.Run("panics on invalid selection mode", func(t *testing.T) { + node := newTestNode(t, testNodeOpts{ + config: testNodeConfig{syncThreshold: 1}, + }) + node.nLiveNodes = func() (count int, blockNumber int64, totalDifficulty *utils.Big) { + return + } + assert.Panics(t, func() { + _, _ = node.syncStatus(0, nil) + }) + }) + t.Run("block height selection mode", func(t *testing.T) { + const syncThreshold = 10 + const highestBlock = 1000 + const nodesNum = 20 + const totalDifficulty = 3000 + testCases := []struct { + name string + blockNumber int64 + outOfSync bool + }{ + { + name: "below threshold", + blockNumber: highestBlock - syncThreshold - 1, + outOfSync: true, + }, + { + name: "equal to threshold", + blockNumber: highestBlock - syncThreshold, + outOfSync: false, + }, + { + name: "equal to highest block", + blockNumber: highestBlock, + outOfSync: false, + }, + { + name: "higher than highest block", + blockNumber: highestBlock, + outOfSync: false, + }, + } + + for _, selectionMode := range []string{NodeSelectionModeHighestHead, NodeSelectionModeRoundRobin, NodeSelectionModePriorityLevel} { + node := newTestNode(t, testNodeOpts{ + config: testNodeConfig{ + syncThreshold: syncThreshold, + selectionMode: selectionMode, + }, + }) + node.nLiveNodes = func() (int, int64, *utils.Big) { + return nodesNum, highestBlock, utils.NewBigI(totalDifficulty) + } + for _, td := range []int64{totalDifficulty - syncThreshold - 1, totalDifficulty - syncThreshold, totalDifficulty, totalDifficulty + 1} { + for _, testCase := range testCases { + t.Run(fmt.Sprintf("%s: selectionMode: %s: total difficulty: %d", testCase.name, selectionMode, td), func(t *testing.T) { + outOfSync, liveNodes := node.syncStatus(testCase.blockNumber, utils.NewBigI(td)) + assert.Equal(t, nodesNum, liveNodes) + assert.Equal(t, testCase.outOfSync, outOfSync) + }) + } + } + } + + }) + t.Run("total difficulty selection mode", func(t *testing.T) { + const syncThreshold = 10 + const highestBlock = 1000 + const nodesNum = 20 + const totalDifficulty = 3000 + testCases := []struct { + name string + totalDifficulty int64 + outOfSync bool + }{ + { + name: "below threshold", + totalDifficulty: totalDifficulty - syncThreshold - 1, + outOfSync: true, + }, + { + name: "equal to threshold", + totalDifficulty: totalDifficulty - syncThreshold, + outOfSync: false, + }, + { + name: "equal to highest block", + totalDifficulty: totalDifficulty, + outOfSync: false, + }, + { + name: "higher than highest block", + totalDifficulty: totalDifficulty, + outOfSync: false, + }, + } + + node := newTestNode(t, testNodeOpts{ + config: testNodeConfig{ + syncThreshold: syncThreshold, + selectionMode: NodeSelectionModeTotalDifficulty, + }, + }) + node.nLiveNodes = func() (int, int64, *utils.Big) { + return nodesNum, highestBlock, utils.NewBigI(totalDifficulty) + } + for _, hb := range []int64{highestBlock - syncThreshold - 1, highestBlock - syncThreshold, highestBlock, highestBlock + 1} { + for _, testCase := range testCases { + t.Run(fmt.Sprintf("%s: selectionMode: %s: highest block: %d", testCase.name, NodeSelectionModeTotalDifficulty, hb), func(t *testing.T) { + outOfSync, liveNodes := node.syncStatus(hb, utils.NewBigI(testCase.totalDifficulty)) + assert.Equal(t, nodesNum, liveNodes) + assert.Equal(t, testCase.outOfSync, outOfSync) + }) + } + } + + }) +} diff --git a/common/client/node_selector.go b/common/client/node_selector.go new file mode 100644 index 00000000000..45604ebe8d9 --- /dev/null +++ b/common/client/node_selector.go @@ -0,0 +1,46 @@ +package client + +import ( + "fmt" + + "github.com/smartcontractkit/chainlink/v2/common/types" +) + +const ( + NodeSelectionModeHighestHead = "HighestHead" + NodeSelectionModeRoundRobin = "RoundRobin" + NodeSelectionModeTotalDifficulty = "TotalDifficulty" + NodeSelectionModePriorityLevel = "PriorityLevel" +) + +//go:generate mockery --quiet --name NodeSelector --structname mockNodeSelector --filename "mock_node_selector_test.go" --inpackage --case=underscore +type NodeSelector[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +] interface { + // Select returns a Node, or nil if none can be selected. + // Implementation must be thread-safe. + Select() Node[CHAIN_ID, HEAD, RPC] + // Name returns the strategy name, e.g. "HighestHead" or "RoundRobin" + Name() string +} + +func newNodeSelector[ + CHAIN_ID types.ID, + HEAD Head, + RPC NodeClient[CHAIN_ID, HEAD], +](selectionMode string, nodes []Node[CHAIN_ID, HEAD, RPC]) NodeSelector[CHAIN_ID, HEAD, RPC] { + switch selectionMode { + case NodeSelectionModeHighestHead: + return NewHighestHeadNodeSelector[CHAIN_ID, HEAD, RPC](nodes) + case NodeSelectionModeRoundRobin: + return NewRoundRobinSelector[CHAIN_ID, HEAD, RPC](nodes) + case NodeSelectionModeTotalDifficulty: + return NewTotalDifficultyNodeSelector[CHAIN_ID, HEAD, RPC](nodes) + case NodeSelectionModePriorityLevel: + return NewPriorityLevelNodeSelector[CHAIN_ID, HEAD, RPC](nodes) + default: + panic(fmt.Sprintf("unsupported NodeSelectionMode: %s", selectionMode)) + } +} diff --git a/common/client/node_selector_highest_head_test.go b/common/client/node_selector_highest_head_test.go new file mode 100644 index 00000000000..6e47bbedcae --- /dev/null +++ b/common/client/node_selector_highest_head_test.go @@ -0,0 +1,176 @@ +package client + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/smartcontractkit/chainlink/v2/common/types" +) + +func TestHighestHeadNodeSelectorName(t *testing.T) { + selector := newNodeSelector[types.ID, Head, NodeClient[types.ID, Head]](NodeSelectionModeHighestHead, nil) + assert.Equal(t, selector.Name(), NodeSelectionModeHighestHead) +} + +func TestHighestHeadNodeSelector(t *testing.T) { + t.Parallel() + + type nodeClient NodeClient[types.ID, Head] + + var nodes []Node[types.ID, Head, nodeClient] + + for i := 0; i < 3; i++ { + node := newMockNode[types.ID, Head, nodeClient](t) + if i == 0 { + // first node is out of sync + node.On("StateAndLatest").Return(nodeStateOutOfSync, int64(-1), nil) + } else if i == 1 { + // second node is alive, LatestReceivedBlockNumber = 1 + node.On("StateAndLatest").Return(nodeStateAlive, int64(1), nil) + } else { + // third node is alive, LatestReceivedBlockNumber = 2 (best node) + node.On("StateAndLatest").Return(nodeStateAlive, int64(2), nil) + } + node.On("Order").Maybe().Return(int32(1)) + nodes = append(nodes, node) + } + + selector := newNodeSelector[types.ID, Head, nodeClient](NodeSelectionModeHighestHead, nodes) + assert.Same(t, nodes[2], selector.Select()) + + t.Run("stick to the same node", func(t *testing.T) { + node := newMockNode[types.ID, Head, nodeClient](t) + // fourth node is alive, LatestReceivedBlockNumber = 2 (same as 3rd) + node.On("StateAndLatest").Return(nodeStateAlive, int64(2), nil) + node.On("Order").Return(int32(1)) + nodes = append(nodes, node) + + selector := newNodeSelector(NodeSelectionModeHighestHead, nodes) + assert.Same(t, nodes[2], selector.Select()) + }) + + t.Run("another best node", func(t *testing.T) { + node := newMockNode[types.ID, Head, nodeClient](t) + // fifth node is alive, LatestReceivedBlockNumber = 3 (better than 3rd and 4th) + node.On("StateAndLatest").Return(nodeStateAlive, int64(3), nil) + node.On("Order").Return(int32(1)) + nodes = append(nodes, node) + + selector := newNodeSelector(NodeSelectionModeHighestHead, nodes) + assert.Same(t, nodes[4], selector.Select()) + }) + + t.Run("nodes never update latest block number", func(t *testing.T) { + node1 := newMockNode[types.ID, Head, nodeClient](t) + node1.On("StateAndLatest").Return(nodeStateAlive, int64(-1), nil) + node1.On("Order").Return(int32(1)) + node2 := newMockNode[types.ID, Head, nodeClient](t) + node2.On("StateAndLatest").Return(nodeStateAlive, int64(-1), nil) + node2.On("Order").Return(int32(1)) + selector := newNodeSelector(NodeSelectionModeHighestHead, []Node[types.ID, Head, nodeClient]{node1, node2}) + assert.Same(t, node1, selector.Select()) + }) +} + +func TestHighestHeadNodeSelector_None(t *testing.T) { + t.Parallel() + + type nodeClient NodeClient[types.ID, Head] + var nodes []Node[types.ID, Head, nodeClient] + + for i := 0; i < 3; i++ { + node := newMockNode[types.ID, Head, nodeClient](t) + if i == 0 { + // first node is out of sync + node.On("StateAndLatest").Return(nodeStateOutOfSync, int64(-1), nil) + } else { + // others are unreachable + node.On("StateAndLatest").Return(nodeStateUnreachable, int64(1), nil) + } + nodes = append(nodes, node) + } + + selector := newNodeSelector(NodeSelectionModeHighestHead, nodes) + assert.Nil(t, selector.Select()) +} + +func TestHighestHeadNodeSelectorWithOrder(t *testing.T) { + t.Parallel() + + type nodeClient NodeClient[types.ID, Head] + var nodes []Node[types.ID, Head, nodeClient] + + t.Run("same head and order", func(t *testing.T) { + for i := 0; i < 3; i++ { + node := newMockNode[types.ID, Head, nodeClient](t) + node.On("StateAndLatest").Return(nodeStateAlive, int64(1), nil) + node.On("Order").Return(int32(2)) + nodes = append(nodes, node) + } + selector := newNodeSelector(NodeSelectionModeHighestHead, nodes) + //Should select the first node because all things are equal + assert.Same(t, nodes[0], selector.Select()) + }) + + t.Run("same head but different order", func(t *testing.T) { + node1 := newMockNode[types.ID, Head, nodeClient](t) + node1.On("StateAndLatest").Return(nodeStateAlive, int64(3), nil) + node1.On("Order").Return(int32(3)) + + node2 := newMockNode[types.ID, Head, nodeClient](t) + node2.On("StateAndLatest").Return(nodeStateAlive, int64(3), nil) + node2.On("Order").Return(int32(1)) + + node3 := newMockNode[types.ID, Head, nodeClient](t) + node3.On("StateAndLatest").Return(nodeStateAlive, int64(3), nil) + node3.On("Order").Return(int32(2)) + + nodes := []Node[types.ID, Head, nodeClient]{node1, node2, node3} + selector := newNodeSelector(NodeSelectionModeHighestHead, nodes) + //Should select the second node as it has the highest priority + assert.Same(t, nodes[1], selector.Select()) + }) + + t.Run("different head but same order", func(t *testing.T) { + node1 := newMockNode[types.ID, Head, nodeClient](t) + node1.On("StateAndLatest").Return(nodeStateAlive, int64(1), nil) + node1.On("Order").Maybe().Return(int32(3)) + + node2 := newMockNode[types.ID, Head, nodeClient](t) + node2.On("StateAndLatest").Return(nodeStateAlive, int64(2), nil) + node2.On("Order").Maybe().Return(int32(3)) + + node3 := newMockNode[types.ID, Head, nodeClient](t) + node3.On("StateAndLatest").Return(nodeStateAlive, int64(3), nil) + node3.On("Order").Return(int32(3)) + + nodes := []Node[types.ID, Head, nodeClient]{node1, node2, node3} + selector := newNodeSelector(NodeSelectionModeHighestHead, nodes) + //Should select the third node as it has the highest head + assert.Same(t, nodes[2], selector.Select()) + }) + + t.Run("different head and different order", func(t *testing.T) { + node1 := newMockNode[types.ID, Head, nodeClient](t) + node1.On("StateAndLatest").Return(nodeStateAlive, int64(10), nil) + node1.On("Order").Maybe().Return(int32(3)) + + node2 := newMockNode[types.ID, Head, nodeClient](t) + node2.On("StateAndLatest").Return(nodeStateAlive, int64(11), nil) + node2.On("Order").Maybe().Return(int32(4)) + + node3 := newMockNode[types.ID, Head, nodeClient](t) + node3.On("StateAndLatest").Return(nodeStateAlive, int64(11), nil) + node3.On("Order").Maybe().Return(int32(3)) + + node4 := newMockNode[types.ID, Head, nodeClient](t) + node4.On("StateAndLatest").Return(nodeStateAlive, int64(10), nil) + node4.On("Order").Maybe().Return(int32(1)) + + nodes := []Node[types.ID, Head, nodeClient]{node1, node2, node3, node4} + selector := newNodeSelector(NodeSelectionModeHighestHead, nodes) + //Should select the third node as it has the highest head and will win the priority tie-breaker + assert.Same(t, nodes[2], selector.Select()) + }) +} diff --git a/common/client/node_selector_priority_level_test.go b/common/client/node_selector_priority_level_test.go new file mode 100644 index 00000000000..ac84645e91c --- /dev/null +++ b/common/client/node_selector_priority_level_test.go @@ -0,0 +1,88 @@ +package client + +import ( + "testing" + + "github.com/smartcontractkit/chainlink/v2/common/types" + + "github.com/stretchr/testify/assert" +) + +func TestPriorityLevelNodeSelectorName(t *testing.T) { + selector := newNodeSelector[types.ID, Head, NodeClient[types.ID, Head]](NodeSelectionModePriorityLevel, nil) + assert.Equal(t, selector.Name(), NodeSelectionModePriorityLevel) +} + +func TestPriorityLevelNodeSelector(t *testing.T) { + t.Parallel() + + type nodeClient NodeClient[types.ID, Head] + var nodes []Node[types.ID, Head, nodeClient] + n1 := newMockNode[types.ID, Head, nodeClient](t) + n1.On("State").Return(nodeStateAlive) + n1.On("Order").Return(int32(1)) + + n2 := newMockNode[types.ID, Head, nodeClient](t) + n2.On("State").Return(nodeStateAlive) + n2.On("Order").Return(int32(1)) + + n3 := newMockNode[types.ID, Head, nodeClient](t) + n3.On("State").Return(nodeStateAlive) + n3.On("Order").Return(int32(1)) + + nodes = append(nodes, n1, n2, n3) + selector := newNodeSelector(NodeSelectionModePriorityLevel, nodes) + assert.Same(t, nodes[0], selector.Select()) + assert.Same(t, nodes[1], selector.Select()) + assert.Same(t, nodes[2], selector.Select()) + assert.Same(t, nodes[0], selector.Select()) + assert.Same(t, nodes[1], selector.Select()) + assert.Same(t, nodes[2], selector.Select()) +} + +func TestPriorityLevelNodeSelector_None(t *testing.T) { + t.Parallel() + + type nodeClient NodeClient[types.ID, Head] + var nodes []Node[types.ID, Head, nodeClient] + + for i := 0; i < 3; i++ { + node := newMockNode[types.ID, Head, nodeClient](t) + if i == 0 { + // first node is out of sync + node.On("State").Return(nodeStateOutOfSync) + node.On("Order").Return(int32(1)) + } else { + // others are unreachable + node.On("State").Return(nodeStateUnreachable) + node.On("Order").Return(int32(1)) + } + nodes = append(nodes, node) + } + + selector := newNodeSelector(NodeSelectionModePriorityLevel, nodes) + assert.Nil(t, selector.Select()) +} + +func TestPriorityLevelNodeSelector_DifferentOrder(t *testing.T) { + t.Parallel() + + type nodeClient NodeClient[types.ID, Head] + var nodes []Node[types.ID, Head, nodeClient] + n1 := newMockNode[types.ID, Head, nodeClient](t) + n1.On("State").Return(nodeStateAlive) + n1.On("Order").Return(int32(1)) + + n2 := newMockNode[types.ID, Head, nodeClient](t) + n2.On("State").Return(nodeStateAlive) + n2.On("Order").Return(int32(2)) + + n3 := newMockNode[types.ID, Head, nodeClient](t) + n3.On("State").Return(nodeStateAlive) + n3.On("Order").Return(int32(3)) + + nodes = append(nodes, n1, n2, n3) + selector := newNodeSelector(NodeSelectionModePriorityLevel, nodes) + assert.Same(t, nodes[0], selector.Select()) + assert.Same(t, nodes[0], selector.Select()) +} diff --git a/common/client/node_selector_round_robin_test.go b/common/client/node_selector_round_robin_test.go new file mode 100644 index 00000000000..e5078d858f1 --- /dev/null +++ b/common/client/node_selector_round_robin_test.go @@ -0,0 +1,61 @@ +package client + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/smartcontractkit/chainlink/v2/common/types" +) + +func TestRoundRobinNodeSelectorName(t *testing.T) { + selector := newNodeSelector[types.ID, Head, NodeClient[types.ID, Head]](NodeSelectionModeRoundRobin, nil) + assert.Equal(t, selector.Name(), NodeSelectionModeRoundRobin) +} + +func TestRoundRobinNodeSelector(t *testing.T) { + t.Parallel() + + type nodeClient NodeClient[types.ID, Head] + var nodes []Node[types.ID, Head, nodeClient] + + for i := 0; i < 3; i++ { + node := newMockNode[types.ID, Head, nodeClient](t) + if i == 0 { + // first node is out of sync + node.On("State").Return(nodeStateOutOfSync) + } else { + // second & third nodes are alive + node.On("State").Return(nodeStateAlive) + } + nodes = append(nodes, node) + } + + selector := newNodeSelector(NodeSelectionModeRoundRobin, nodes) + assert.Same(t, nodes[1], selector.Select()) + assert.Same(t, nodes[2], selector.Select()) + assert.Same(t, nodes[1], selector.Select()) + assert.Same(t, nodes[2], selector.Select()) +} + +func TestRoundRobinNodeSelector_None(t *testing.T) { + t.Parallel() + + type nodeClient NodeClient[types.ID, Head] + var nodes []Node[types.ID, Head, nodeClient] + + for i := 0; i < 3; i++ { + node := newMockNode[types.ID, Head, nodeClient](t) + if i == 0 { + // first node is out of sync + node.On("State").Return(nodeStateOutOfSync) + } else { + // others are unreachable + node.On("State").Return(nodeStateUnreachable) + } + nodes = append(nodes, node) + } + + selector := newNodeSelector(NodeSelectionModeRoundRobin, nodes) + assert.Nil(t, selector.Select()) +} diff --git a/common/client/node_selector_test.go b/common/client/node_selector_test.go new file mode 100644 index 00000000000..226cb67168d --- /dev/null +++ b/common/client/node_selector_test.go @@ -0,0 +1,18 @@ +package client + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/smartcontractkit/chainlink/v2/common/types" +) + +func TestNodeSelector(t *testing.T) { + // rest of the tests are located in specific node selectors tests + t.Run("panics on unknown type", func(t *testing.T) { + assert.Panics(t, func() { + _ = newNodeSelector[types.ID, Head, NodeClient[types.ID, Head]]("unknown", nil) + }) + }) +} diff --git a/common/client/node_selector_total_difficulty_test.go b/common/client/node_selector_total_difficulty_test.go new file mode 100644 index 00000000000..4eecb859db9 --- /dev/null +++ b/common/client/node_selector_total_difficulty_test.go @@ -0,0 +1,178 @@ +package client + +import ( + "testing" + + "github.com/smartcontractkit/chainlink/v2/common/types" + "github.com/smartcontractkit/chainlink/v2/core/utils" + + "github.com/stretchr/testify/assert" +) + +func TestTotalDifficultyNodeSelectorName(t *testing.T) { + selector := newNodeSelector[types.ID, Head, NodeClient[types.ID, Head]](NodeSelectionModeTotalDifficulty, nil) + assert.Equal(t, selector.Name(), NodeSelectionModeTotalDifficulty) +} + +func TestTotalDifficultyNodeSelector(t *testing.T) { + t.Parallel() + + type nodeClient NodeClient[types.ID, Head] + var nodes []Node[types.ID, Head, nodeClient] + + for i := 0; i < 3; i++ { + node := newMockNode[types.ID, Head, nodeClient](t) + if i == 0 { + // first node is out of sync + node.On("StateAndLatest").Return(nodeStateOutOfSync, int64(-1), nil) + } else if i == 1 { + // second node is alive + node.On("StateAndLatest").Return(nodeStateAlive, int64(1), utils.NewBigI(7)) + } else { + // third node is alive and best + node.On("StateAndLatest").Return(nodeStateAlive, int64(2), utils.NewBigI(8)) + } + node.On("Order").Maybe().Return(int32(1)) + nodes = append(nodes, node) + } + + selector := newNodeSelector(NodeSelectionModeTotalDifficulty, nodes) + assert.Same(t, nodes[2], selector.Select()) + + t.Run("stick to the same node", func(t *testing.T) { + node := newMockNode[types.ID, Head, nodeClient](t) + // fourth node is alive (same as 3rd) + node.On("StateAndLatest").Return(nodeStateAlive, int64(2), utils.NewBigI(8)) + node.On("Order").Maybe().Return(int32(1)) + nodes = append(nodes, node) + + selector := newNodeSelector(NodeSelectionModeTotalDifficulty, nodes) + assert.Same(t, nodes[2], selector.Select()) + }) + + t.Run("another best node", func(t *testing.T) { + node := newMockNode[types.ID, Head, nodeClient](t) + // fifth node is alive (better than 3rd and 4th) + node.On("StateAndLatest").Return(nodeStateAlive, int64(3), utils.NewBigI(11)) + node.On("Order").Maybe().Return(int32(1)) + nodes = append(nodes, node) + + selector := newNodeSelector(NodeSelectionModeTotalDifficulty, nodes) + assert.Same(t, nodes[4], selector.Select()) + }) + + t.Run("nodes never update latest block number", func(t *testing.T) { + node1 := newMockNode[types.ID, Head, nodeClient](t) + node1.On("StateAndLatest").Return(nodeStateAlive, int64(-1), nil) + node1.On("Order").Maybe().Return(int32(1)) + node2 := newMockNode[types.ID, Head, nodeClient](t) + node2.On("StateAndLatest").Return(nodeStateAlive, int64(-1), nil) + node2.On("Order").Maybe().Return(int32(1)) + nodes := []Node[types.ID, Head, nodeClient]{node1, node2} + + selector := newNodeSelector(NodeSelectionModeTotalDifficulty, nodes) + assert.Same(t, node1, selector.Select()) + }) +} + +func TestTotalDifficultyNodeSelector_None(t *testing.T) { + t.Parallel() + + type nodeClient NodeClient[types.ID, Head] + var nodes []Node[types.ID, Head, nodeClient] + + for i := 0; i < 3; i++ { + node := newMockNode[types.ID, Head, nodeClient](t) + if i == 0 { + // first node is out of sync + node.On("StateAndLatest").Return(nodeStateOutOfSync, int64(-1), nil) + } else { + // others are unreachable + node.On("StateAndLatest").Return(nodeStateUnreachable, int64(1), utils.NewBigI(7)) + } + nodes = append(nodes, node) + } + + selector := newNodeSelector(NodeSelectionModeTotalDifficulty, nodes) + assert.Nil(t, selector.Select()) +} + +func TestTotalDifficultyNodeSelectorWithOrder(t *testing.T) { + t.Parallel() + + type nodeClient NodeClient[types.ID, Head] + var nodes []Node[types.ID, Head, nodeClient] + + t.Run("same td and order", func(t *testing.T) { + for i := 0; i < 3; i++ { + node := newMockNode[types.ID, Head, nodeClient](t) + node.On("StateAndLatest").Return(nodeStateAlive, int64(1), utils.NewBigI(10)) + node.On("Order").Return(int32(2)) + nodes = append(nodes, node) + } + selector := newNodeSelector(NodeSelectionModeTotalDifficulty, nodes) + //Should select the first node because all things are equal + assert.Same(t, nodes[0], selector.Select()) + }) + + t.Run("same td but different order", func(t *testing.T) { + node1 := newMockNode[types.ID, Head, nodeClient](t) + node1.On("StateAndLatest").Return(nodeStateAlive, int64(3), utils.NewBigI(10)) + node1.On("Order").Return(int32(3)) + + node2 := newMockNode[types.ID, Head, nodeClient](t) + node2.On("StateAndLatest").Return(nodeStateAlive, int64(3), utils.NewBigI(10)) + node2.On("Order").Return(int32(1)) + + node3 := newMockNode[types.ID, Head, nodeClient](t) + node3.On("StateAndLatest").Return(nodeStateAlive, int64(3), utils.NewBigI(10)) + node3.On("Order").Return(int32(2)) + + nodes := []Node[types.ID, Head, nodeClient]{node1, node2, node3} + selector := newNodeSelector(NodeSelectionModeTotalDifficulty, nodes) + //Should select the second node as it has the highest priority + assert.Same(t, nodes[1], selector.Select()) + }) + + t.Run("different td but same order", func(t *testing.T) { + node1 := newMockNode[types.ID, Head, nodeClient](t) + node1.On("StateAndLatest").Return(nodeStateAlive, int64(1), utils.NewBigI(10)) + node1.On("Order").Maybe().Return(int32(3)) + + node2 := newMockNode[types.ID, Head, nodeClient](t) + node2.On("StateAndLatest").Return(nodeStateAlive, int64(1), utils.NewBigI(11)) + node2.On("Order").Maybe().Return(int32(3)) + + node3 := newMockNode[types.ID, Head, nodeClient](t) + node3.On("StateAndLatest").Return(nodeStateAlive, int64(1), utils.NewBigI(12)) + node3.On("Order").Return(int32(3)) + + nodes := []Node[types.ID, Head, nodeClient]{node1, node2, node3} + selector := newNodeSelector(NodeSelectionModeTotalDifficulty, nodes) + //Should select the third node as it has the highest td + assert.Same(t, nodes[2], selector.Select()) + }) + + t.Run("different head and different order", func(t *testing.T) { + node1 := newMockNode[types.ID, Head, nodeClient](t) + node1.On("StateAndLatest").Return(nodeStateAlive, int64(1), utils.NewBigI(100)) + node1.On("Order").Maybe().Return(int32(4)) + + node2 := newMockNode[types.ID, Head, nodeClient](t) + node2.On("StateAndLatest").Return(nodeStateAlive, int64(1), utils.NewBigI(110)) + node2.On("Order").Maybe().Return(int32(5)) + + node3 := newMockNode[types.ID, Head, nodeClient](t) + node3.On("StateAndLatest").Return(nodeStateAlive, int64(1), utils.NewBigI(110)) + node3.On("Order").Maybe().Return(int32(1)) + + node4 := newMockNode[types.ID, Head, nodeClient](t) + node4.On("StateAndLatest").Return(nodeStateAlive, int64(1), utils.NewBigI(105)) + node4.On("Order").Maybe().Return(int32(2)) + + nodes := []Node[types.ID, Head, nodeClient]{node1, node2, node3, node4} + selector := newNodeSelector(NodeSelectionModeTotalDifficulty, nodes) + //Should select the third node as it has the highest td and will win the priority tie-breaker + assert.Same(t, nodes[2], selector.Select()) + }) +} diff --git a/common/client/node_test.go b/common/client/node_test.go new file mode 100644 index 00000000000..0438e11e612 --- /dev/null +++ b/common/client/node_test.go @@ -0,0 +1,80 @@ +package client + +import ( + "net/url" + "testing" + "time" + + "github.com/smartcontractkit/chainlink/v2/common/types" + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +type testNodeConfig struct { + pollFailureThreshold uint32 + pollInterval time.Duration + selectionMode string + syncThreshold uint32 +} + +func (n testNodeConfig) PollFailureThreshold() uint32 { + return n.pollFailureThreshold +} + +func (n testNodeConfig) PollInterval() time.Duration { + return n.pollInterval +} + +func (n testNodeConfig) SelectionMode() string { + return n.selectionMode +} + +func (n testNodeConfig) SyncThreshold() uint32 { + return n.syncThreshold +} + +type testNode struct { + *node[types.ID, Head, NodeClient[types.ID, Head]] +} + +type testNodeOpts struct { + config testNodeConfig + noNewHeadsThreshold time.Duration + lggr logger.Logger + wsuri url.URL + httpuri *url.URL + name string + id int32 + chainID types.ID + nodeOrder int32 + rpc *mockNodeClient[types.ID, Head] + chainFamily string +} + +func newTestNode(t *testing.T, opts testNodeOpts) testNode { + if opts.lggr == nil { + opts.lggr = logger.TestLogger(t) + } + + if opts.name == "" { + opts.name = "tes node" + } + + if opts.chainFamily == "" { + opts.chainFamily = "test node chain family" + } + + if opts.chainID == nil { + opts.chainID = types.RandomID() + } + + if opts.id == 0 { + opts.id = 42 + } + + nodeI := NewNode[types.ID, Head, NodeClient[types.ID, Head]](opts.config, opts.noNewHeadsThreshold, opts.lggr, + opts.wsuri, opts.httpuri, opts.name, opts.id, opts.chainID, opts.nodeOrder, opts.rpc, opts.chainFamily) + + return testNode{ + nodeI.(*node[types.ID, Head, NodeClient[types.ID, Head]]), + } +} diff --git a/common/client/send_only_node.go b/common/client/send_only_node.go index 0051fb014d9..fa793a826a6 100644 --- a/common/client/send_only_node.go +++ b/common/client/send_only_node.go @@ -13,6 +13,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" ) +//go:generate mockery --quiet --name sendOnlyClient --structname mockSendOnlyClient --filename "mock_send_only_client_test.go" --inpackage --case=underscore type sendOnlyClient[ CHAIN_ID types.ID, ] interface { @@ -22,6 +23,8 @@ type sendOnlyClient[ } // SendOnlyNode represents one node used as a sendonly +// +//go:generate mockery --quiet --name SendOnlyNode --structname mockSendOnlyNode --filename "mock_send_only_node_test.go" --inpackage --case=underscore type SendOnlyNode[ CHAIN_ID types.ID, RPC sendOnlyClient[CHAIN_ID], @@ -143,6 +146,7 @@ func (s *sendOnlyNode[CHAIN_ID, RPC]) start(startCtx context.Context) { func (s *sendOnlyNode[CHAIN_ID, RPC]) Close() error { return s.StopOnce(s.name, func() error { s.rpc.Close() + close(s.chStop) s.wg.Wait() s.setState(nodeStateClosed) return nil diff --git a/common/client/send_only_node_test.go b/common/client/send_only_node_test.go new file mode 100644 index 00000000000..bfe55153656 --- /dev/null +++ b/common/client/send_only_node_test.go @@ -0,0 +1,139 @@ +package client + +import ( + "fmt" + "net/url" + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "go.uber.org/zap" + + "github.com/smartcontractkit/chainlink-relay/pkg/utils/tests" + + "github.com/smartcontractkit/chainlink/v2/common/types" + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +func TestNewSendOnlyNode(t *testing.T) { + t.Parallel() + + urlFormat := "http://user:%s@testurl.com" + password := "pass" + u, err := url.Parse(fmt.Sprintf(urlFormat, password)) + require.NoError(t, err) + redacted := fmt.Sprintf(urlFormat, "xxxxx") + lggr := logger.TestLogger(t) + name := "TestNewSendOnlyNode" + chainID := types.RandomID() + client := newMockSendOnlyClient[types.ID](t) + + node := NewSendOnlyNode(lggr, *u, name, chainID, client) + assert.NotNil(t, node) + + // Must contain name & url with redacted password + assert.Contains(t, node.String(), fmt.Sprintf("%s:%s", name, redacted)) + assert.Equal(t, node.ConfiguredChainID(), chainID) +} + +func TestStartSendOnlyNode(t *testing.T) { + t.Parallel() + t.Run("becomes unusable if initial dial fails", func(t *testing.T) { + t.Parallel() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + client := newMockSendOnlyClient[types.ID](t) + client.On("Close").Once() + expectedError := errors.New("some http error") + client.On("DialHTTP").Return(expectedError).Once() + s := NewSendOnlyNode(lggr, url.URL{}, t.Name(), types.RandomID(), client) + + defer func() { assert.NoError(t, s.Close()) }() + err := s.Start(tests.Context(t)) + require.NoError(t, err) + + assert.Equal(t, nodeStateUnusable, s.State()) + tests.RequireLogMessage(t, observedLogs, "Dial failed: SendOnly Node is unusable") + }) + t.Run("Default ChainID(0) produces warn and skips checks", func(t *testing.T) { + t.Parallel() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + client := newMockSendOnlyClient[types.ID](t) + client.On("Close").Once() + client.On("DialHTTP").Return(nil).Once() + s := NewSendOnlyNode(lggr, url.URL{}, t.Name(), types.NewIDFromInt(0), client) + + defer func() { assert.NoError(t, s.Close()) }() + err := s.Start(tests.Context(t)) + require.NoError(t, err) + + assert.Equal(t, nodeStateAlive, s.State()) + tests.RequireLogMessage(t, observedLogs, "sendonly rpc ChainID verification skipped") + }) + t.Run("Can recover from chainID verification failure", func(t *testing.T) { + t.Parallel() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + client := newMockSendOnlyClient[types.ID](t) + client.On("Close").Once() + client.On("DialHTTP").Return(nil) + expectedError := errors.New("failed to get chain ID") + chainID := types.RandomID() + const failuresCount = 2 + client.On("ChainID", mock.Anything).Return(types.RandomID(), expectedError).Times(failuresCount) + client.On("ChainID", mock.Anything).Return(chainID, nil) + + s := NewSendOnlyNode(lggr, url.URL{}, t.Name(), chainID, client) + + defer func() { assert.NoError(t, s.Close()) }() + err := s.Start(tests.Context(t)) + require.NoError(t, err) + + assert.Equal(t, nodeStateUnreachable, s.State()) + tests.AssertLogCountEventually(t, observedLogs, fmt.Sprintf("Verify failed: %v", expectedError), failuresCount) + tests.AssertEventually(t, func() bool { + return s.State() == nodeStateAlive + }) + }) + t.Run("Can recover from chainID mismatch", func(t *testing.T) { + t.Parallel() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + client := newMockSendOnlyClient[types.ID](t) + client.On("Close").Once() + client.On("DialHTTP").Return(nil).Once() + configuredChainID := types.NewIDFromInt(11) + rpcChainID := types.NewIDFromInt(20) + const failuresCount = 2 + client.On("ChainID", mock.Anything).Return(rpcChainID, nil).Times(failuresCount) + client.On("ChainID", mock.Anything).Return(configuredChainID, nil) + s := NewSendOnlyNode(lggr, url.URL{}, t.Name(), configuredChainID, client) + + defer func() { assert.NoError(t, s.Close()) }() + err := s.Start(tests.Context(t)) + require.NoError(t, err) + + assert.Equal(t, nodeStateInvalidChainID, s.State()) + tests.AssertLogCountEventually(t, observedLogs, "sendonly rpc ChainID doesn't match local chain ID", failuresCount) + tests.AssertEventually(t, func() bool { + return s.State() == nodeStateAlive + }) + }) + t.Run("Start with Random ChainID", func(t *testing.T) { + t.Parallel() + lggr, observedLogs := logger.TestLoggerObserved(t, zap.WarnLevel) + client := newMockSendOnlyClient[types.ID](t) + client.On("Close").Once() + client.On("DialHTTP").Return(nil).Once() + configuredChainID := types.RandomID() + client.On("ChainID", mock.Anything).Return(configuredChainID, nil) + s := NewSendOnlyNode(lggr, url.URL{}, t.Name(), configuredChainID, client) + + defer func() { assert.NoError(t, s.Close()) }() + err := s.Start(tests.Context(t)) + assert.NoError(t, err) + tests.AssertEventually(t, func() bool { + return s.State() == nodeStateAlive + }) + assert.Equal(t, 0, observedLogs.Len()) // No warnings expected + }) +} diff --git a/common/client/types.go b/common/client/types.go index f3a6029a9e8..0e52f1db72c 100644 --- a/common/client/types.go +++ b/common/client/types.go @@ -11,6 +11,8 @@ import ( ) // RPC includes all the necessary methods for a multi-node client to interact directly with any RPC endpoint. +// +//go:generate mockery --quiet --name RPC --structname mockRPC --inpackage --filename "mock_rpc_test.go" --case=underscore type RPC[ CHAIN_ID types.ID, SEQ types.Sequence, @@ -45,12 +47,16 @@ type RPC[ } // Head is the interface required by the NodeClient +// +//go:generate mockery --quiet --name Head --structname mockHead --filename "mock_head_test.go" --inpackage --case=underscore type Head interface { BlockNumber() int64 BlockDifficulty() *utils.Big } // NodeClient includes all the necessary RPC methods required by a node. +// +//go:generate mockery --quiet --name NodeClient --structname mockNodeClient --filename "mock_node_client_test.go" --inpackage --case=underscore type NodeClient[ CHAIN_ID types.ID, HEAD Head, diff --git a/common/types/test_utils.go b/common/types/test_utils.go new file mode 100644 index 00000000000..40560f7866c --- /dev/null +++ b/common/types/test_utils.go @@ -0,0 +1,16 @@ +package types + +import ( + "math" + "math/big" + "math/rand" +) + +func RandomID() ID { + id := rand.Int63n(math.MaxInt32) + 10000 + return big.NewInt(id) +} + +func NewIDFromInt(id int64) ID { + return big.NewInt(id) +} From d8dc7abe3c9bd9bedd036cf69c742e883832fc9e Mon Sep 17 00:00:00 2001 From: Justin Kaseman Date: Thu, 9 Nov 2023 16:09:14 -0500 Subject: [PATCH 5/7] [Functions] Add Billing event (#11185) * FUN-974 - Add Billing event * Add L1 fee share to billing event * Update gas snapshot --- .../gas-snapshots/functions.gas-snapshot | 44 +++--- .../functions/dev/v1_X/FunctionsBilling.sol | 19 ++- .../tests/v1_X/FunctionsBilling.t.sol | 52 ++++++- .../functions_coordinator.go | 147 +++++++++++++++++- ...rapper-dependency-versions-do-not-edit.txt | 2 +- 5 files changed, 237 insertions(+), 27 deletions(-) diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index 4e891535b77..af95b75df10 100644 --- a/contracts/gas-snapshots/functions.gas-snapshot +++ b/contracts/gas-snapshots/functions.gas-snapshot @@ -1,12 +1,12 @@ -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 14497117) -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14497095) -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14497111) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14508531) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14508508) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14508480) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14508431) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14508420) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14508464) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 14534216) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14534194) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14534210) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14545630) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14545607) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14545579) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14545530) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14545519) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14545563) FunctionsBilling_Constructor:test_Constructor_Success() (gas: 14812) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_RevertIfNotRouter() (gas: 13282) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_Success() (gas: 15897) @@ -26,9 +26,11 @@ FunctionsBilling_OracleWithdrawAll:test_OracleWithdrawAll_SuccessPaysTransmitter FunctionsBilling_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 18974) FunctionsBilling_UpdateConfig:test_UpdateConfig_Success() (gas: 38251) FunctionsBilling__DisperseFeePool:test__DisperseFeePool_RevertIfNotSet() (gas: 8801) +FunctionsBilling__FulfillAndBill:test__FulfillAndBill_RevertIfInvalidCommitment() (gas: 13302) +FunctionsBilling__FulfillAndBill:test__FulfillAndBill_Success() (gas: 180763) FunctionsClient_Constructor:test_Constructor_Success() (gas: 7573) -FunctionsClient_FulfillRequest:test_FulfillRequest_MaximumGas() (gas: 501740) -FunctionsClient_FulfillRequest:test_FulfillRequest_MinimumGas() (gas: 202944) +FunctionsClient_FulfillRequest:test_FulfillRequest_MaximumGas() (gas: 504364) +FunctionsClient_FulfillRequest:test_FulfillRequest_MinimumGas() (gas: 205568) FunctionsClient_HandleOracleFulfillment:test_HandleOracleFulfillment_RevertIfNotRouter() (gas: 14623) FunctionsClient_HandleOracleFulfillment:test_HandleOracleFulfillment_Success() (gas: 22923) FunctionsClient__SendRequest:test__SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 55059) @@ -49,17 +51,17 @@ FunctionsRequest_DEFAULT_BUFFER_SIZE:test_DEFAULT_BUFFER_SIZE() (gas: 246) FunctionsRequest_EncodeCBOR:test_EncodeCBOR_Success() (gas: 223) FunctionsRequest_REQUEST_DATA_VERSION:test_REQUEST_DATA_VERSION() (gas: 225) FunctionsRouter_Constructor:test_Constructor_Success() (gas: 12007) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 174021) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 164352) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 174037) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 164368) FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidCommitment() (gas: 38115) FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidRequestId() (gas: 35238) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 182497) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 182513) FunctionsRouter_Fulfill:test_Fulfill_RevertIfNotCommittedCoordinator() (gas: 28086) -FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 158041) -FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 323262) -FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 336879) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2512144) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 542628) +FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 158055) +FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 327615) +FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 341236) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2516517) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 546996) FunctionsRouter_GetAdminFee:test_GetAdminFee_Success() (gas: 17983) FunctionsRouter_GetAllowListId:test_GetAllowListId_Success() (gas: 12904) FunctionsRouter_GetConfig:test_GetConfig_Success() (gas: 37159) @@ -142,8 +144,8 @@ FunctionsSubscriptions_GetTotalBalance:test_GetTotalBalance_Success() (gas: 1501 FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata(uint96) (runs: 256, μ: 43685, ~: 45548) FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96) (runs: 256, μ: 46197, ~: 48060) FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink(uint96) (runs: 256, μ: 14295, ~: 14295) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused(uint96) (runs: 256, μ: 51000, ~: 53040) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 85879, ~: 89604) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused(uint96) (runs: 256, μ: 51089, ~: 53040) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 86057, ~: 89604) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfAmountMoreThanBalance() (gas: 20745) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfBalanceInvariant() (gas: 189) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfNoAmount() (gas: 15638) diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol index bf43ead8d72..bd13a3a5a1a 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol @@ -20,6 +20,15 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { using FunctionsResponse for FunctionsResponse.FulfillResult; uint256 private constant REASONABLE_GAS_PRICE_CEILING = 1_000_000_000_000_000; // 1 million gwei + + event RequestBilled( + bytes32 indexed requestId, + uint96 juelsPerGas, + uint256 l1FeeShareWei, + uint96 callbackCostJuels, + uint96 totalCostJuels + ); + // ================================================================ // | Request Commitment state | // ================================================================ @@ -268,12 +277,13 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { uint256 l1FeeShareWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data) / reportBatchSize; // Gas overhead without callback uint96 gasOverheadJuels = _getJuelsFromWei(gasOverheadWei + l1FeeShareWei); + uint96 juelsPerGas = _getJuelsFromWei(tx.gasprice); // The Functions Router will perform the callback to the client contract (FunctionsResponse.FulfillResult resultCode, uint96 callbackCostJuels) = _getRouter().fulfill( response, err, - _getJuelsFromWei(tx.gasprice), // Juels Per Gas conversion rate + juelsPerGas, gasOverheadJuels + commitment.donFee, // cost without callback or admin fee, those will be added by the Router msg.sender, commitment @@ -292,6 +302,13 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { // Put donFee into the pool of fees, to be split later // Saves on storage writes that would otherwise be charged to the user s_feePool += commitment.donFee; + emit RequestBilled({ + requestId: requestId, + juelsPerGas: juelsPerGas, + l1FeeShareWei: l1FeeShareWei, + callbackCostJuels: callbackCostJuels, + totalCostJuels: gasOverheadJuels + callbackCostJuels + commitment.donFee + commitment.adminFee + }); } return resultCode; diff --git a/contracts/src/v0.8/functions/tests/v1_X/FunctionsBilling.t.sol b/contracts/src/v0.8/functions/tests/v1_X/FunctionsBilling.t.sol index 82dea8672c8..6e94e4fc5f7 100644 --- a/contracts/src/v0.8/functions/tests/v1_X/FunctionsBilling.t.sol +++ b/contracts/src/v0.8/functions/tests/v1_X/FunctionsBilling.t.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.19; import {FunctionsCoordinator} from "../../dev/v1_X/FunctionsCoordinator.sol"; import {FunctionsBilling} from "../../dev/v1_X/FunctionsBilling.sol"; import {FunctionsRequest} from "../../dev/v1_X/libraries/FunctionsRequest.sol"; +import {FunctionsResponse} from "../../dev/v1_X/libraries/FunctionsResponse.sol"; import {FunctionsSubscriptions} from "../../dev/v1_X/FunctionsSubscriptions.sol"; import {Routable} from "../../dev/v1_X/Routable.sol"; @@ -221,8 +222,55 @@ contract FunctionsBilling__StartBilling { } /// @notice #_fulfillAndBill -contract FunctionsBilling__FulfillAndBill { - // TODO: make contract internal function helper +contract FunctionsBilling__FulfillAndBill is FunctionsClientRequestSetup { + function test__FulfillAndBill_RevertIfInvalidCommitment() public { + vm.expectRevert(); + s_functionsCoordinator.fulfillAndBill_HARNESS( + s_requests[1].requestId, + new bytes(0), + new bytes(0), + new bytes(0), // malformed commitment data + new bytes(0), + 1 + ); + } + + event RequestBilled( + bytes32 indexed requestId, + uint96 juelsPerGas, + uint256 l1FeeShareWei, + uint96 callbackCostJuels, + uint96 totalCostJuels + ); + + function test__FulfillAndBill_Success() public { + uint96 juelsPerGas = uint96((1e18 * TX_GASPRICE_START) / uint256(LINK_ETH_RATE)); + uint96 callbackCostGas = 5072; // Taken manually + uint96 callbackCostJuels = juelsPerGas * callbackCostGas; + uint96 gasOverheadJuels = juelsPerGas * + (getCoordinatorConfig().gasOverheadBeforeCallback + getCoordinatorConfig().gasOverheadAfterCallback); + + uint96 totalCostJuels = gasOverheadJuels + callbackCostJuels + s_donFee + s_adminFee; + + // topic0 (function signature, always checked), check topic1 (true), NOT topic2 (false), NOT topic3 (false), and data (true). + bool checkTopic1 = true; + bool checkTopic2 = false; + bool checkTopic3 = false; + bool checkData = true; + vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData); + emit RequestBilled(s_requests[1].requestId, juelsPerGas, 0, callbackCostJuels, totalCostJuels); + + FunctionsResponse.FulfillResult resultCode = s_functionsCoordinator.fulfillAndBill_HARNESS( + s_requests[1].requestId, + new bytes(0), + new bytes(0), + abi.encode(s_requests[1].commitment), + new bytes(0), + 1 + ); + + assertEq(uint256(resultCode), uint256(FunctionsResponse.FulfillResult.FULFILLED)); + } } /// @notice #deleteCommitment diff --git a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go index b2e5ec4b09a..397ea3d18bb 100644 --- a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go +++ b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go @@ -71,8 +71,8 @@ type FunctionsResponseRequestMeta struct { } var FunctionsCoordinatorMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"linkToNativeFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPublicKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InconsistentReportData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoTransmittersSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouterOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReportInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustBeSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedPublicKeyChange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedRequestDataVersion\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CommitmentDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"callbackGasLimit\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"OracleResponse\",\"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\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"deleteCommitment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"gasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateCost\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getDONFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getThresholdPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracleWithdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"_f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"_offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"donPublicKey\",\"type\":\"bytes\"}],\"name\":\"setDONPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"thresholdPublicKey\",\"type\":\"bytes\"}],\"name\":\"setThresholdPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"availableBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"}],\"internalType\":\"structFunctionsResponse.RequestMeta\",\"name\":\"request\",\"type\":\"tuple\"}],\"name\":\"startRequest\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"transmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60c06040523480156200001157600080fd5b506040516200556438038062005564833981016040819052620000349162000474565b8282828260013380600081620000915760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c457620000c48162000140565b50505015156080526001600160a01b038116620000f457604051632530e88560e11b815260040160405180910390fd5b6001600160a01b0390811660a052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200013482620001eb565b50505050505062000633565b336001600160a01b038216036200019a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000088565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001f562000349565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160f01b026001600160f01b0364ffffffffff909216600160c81b0264ffffffffff60c81b196001600160481b03909416600160801b0293909316600160801b600160f01b031963ffffffff9586166c010000000000000000000000000263ffffffff60601b19978716680100000000000000000297909716600160401b600160801b0319998716640100000000026001600160401b0319909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e0830151610100840151909216600160e01b026001600160e01b0390921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906200033e9083906200057d565b60405180910390a150565b6200035362000355565b565b6000546001600160a01b03163314620003535760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000088565b80516001600160a01b0381168114620003c957600080fd5b919050565b60405161012081016001600160401b03811182821017156200040057634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff81168114620003c957600080fd5b80516001600160481b0381168114620003c957600080fd5b805164ffffffffff81168114620003c957600080fd5b805161ffff81168114620003c957600080fd5b80516001600160e01b0381168114620003c957600080fd5b60008060008385036101608112156200048c57600080fd5b6200049785620003b1565b935061012080601f1983011215620004ae57600080fd5b620004b8620003ce565b9150620004c86020870162000406565b8252620004d86040870162000406565b6020830152620004eb6060870162000406565b6040830152620004fe6080870162000406565b60608301526200051160a087016200041b565b60808301526200052460c0870162000433565b60a08301526200053760e0870162000449565b60c08301526101006200054c8188016200045c565b60e08401526200055e82880162000406565b90830152509150620005746101408501620003b1565b90509250925092565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151620005d060808401826001600160481b03169052565b5060a0830151620005ea60a084018264ffffffffff169052565b5060c08301516200060160c084018261ffff169052565b5060e08301516200061d60e08401826001600160e01b03169052565b506101009283015163ffffffff16919092015290565b60805160a051614ee16200068360003960008181610845015281816109d301528181610ca601528181610f3a015281816110450152818161183001526133aa0152600061126e0152614ee16000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806381ff7048116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610560578063e4ddcea614610573578063f2fde38b1461058957600080fd5b8063c3f909d4146103b0578063d227d24514610528578063d328a91e1461055857600080fd5b8063a631571e116100bd578063a631571e1461035d578063afcb95d71461037d578063b1dc65a41461039d57600080fd5b806381ff7048146102b557806385b214cf146103225780638da5cb5b1461033557600080fd5b806366316d8d116101455780637f15e1661161011f5780637f15e16614610285578063814118341461029857806381f1b938146102ad57600080fd5b806366316d8d1461026257806379ba5097146102755780637d4807871461027d57600080fd5b8063181f5a7711610176578063181f5a77146101ba5780632a905ccc1461020c57806359b5b7ac1461022e57600080fd5b8063083a5466146101925780631112dadc146101a7575b600080fd5b6101a56101a0366004613857565b61059c565b005b6101a56101b5366004613a00565b6105f1565b6101f66040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e312e300000000081525081565b6040516102039190613b24565b60405180910390f35b610214610841565b60405168ffffffffffffffffff9091168152602001610203565b61021461023c366004613bc5565b50600854700100000000000000000000000000000000900468ffffffffffffffffff1690565b6101a5610270366004613c54565b6108d7565b6101a5610a90565b6101a5610b92565b6101a5610293366004613857565b610d92565b6102a0610de2565b6040516102039190613cde565b6101f6610e51565b6102ff60015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610203565b6101a5610330366004613cf1565b610f22565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610203565b61037061036b366004613d0a565b610fd4565b6040516102039190613e5f565b604080516001815260006020820181905291810191909152606001610203565b6101a56103ab366004613eb3565b611175565b61051b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810468ffffffffffffffffff166080830152790100000000000000000000000000000000000000000000000000810464ffffffffff1660a08301527e01000000000000000000000000000000000000000000000000000000000000900461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08301527c0100000000000000000000000000000000000000000000000000000000900490911661010082015290565b6040516102039190613f6a565b61053b61053636600461405a565b61182c565b6040516bffffffffffffffffffffffff9091168152602001610203565b6101f661198c565b6101a561056e366004614173565b6119e3565b61057b61240f565b604051908152602001610203565b6101a5610597366004614240565b612668565b6105a461267c565b60008190036105df576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105ec8284836142f6565b505050565b6105f96126ff565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff64ffffffffff909216790100000000000000000000000000000000000000000000000000027fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90941670010000000000000000000000000000000002939093167fffff0000000000000000000000000000ffffffffffffffffffffffffffffffff63ffffffff9586166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9787166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e08301516101008401519092167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f518486290610836908390613f6a565b60405180910390a150565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d2919061441c565b905090565b6108df612707565b806bffffffffffffffffffffffff166000036109195750336000908152600a60205260409020546bffffffffffffffffffffffff16610973565b336000908152600a60205260409020546bffffffffffffffffffffffff80831691161015610973576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906109a09084906bffffffffffffffffffffffff16614468565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506109f57f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b158015610a7457600080fd5b505af1158015610a88573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b9a6126ff565b610ba2612707565b6000610bac610de2565b905060005b8151811015610d8e576000600a6000848481518110610bd257610bd261448d565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d7d576000600a6000858581518110610c3157610c3161448d565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610cc87f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610cf557610cf561448d565b6020026020010151836040518363ffffffff1660e01b8152600401610d4a92919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d6457600080fd5b505af1158015610d78573d6000803e3d6000fd5b505050505b50610d87816144bc565b9050610bb1565b5050565b610d9a61267c565b6000819003610dd5576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105ec8284836142f6565b60606006805480602002602001604051908101604052809291908181526020018280548015610e4757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e1c575b5050505050905090565b6060600d8054610e609061425d565b9050600003610e9b576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610ea89061425d565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed49061425d565b8015610e475780601f10610ef657610100808354040283529160200191610e47565b820191906000526020600020905b815481529060010190602001808311610f0457509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f91576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f416906108369083815260200190565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461109c576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110ad6110a8836144f4565b6128b2565b90506110bf6060830160408401614240565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff3261110d60c0870160a088016145e1565b61111f61016088016101408901614240565b61112988806145fe565b61113b6101208b016101008c01614663565b60208b01356111516101008d0160e08e0161467e565b8b6040516111679998979695949392919061469b565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16040805160608101825260025480825260035460ff8082166020850152610100909104169282019290925290831461125c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f6e666967446967657374206d69736d6174636800000000000000000000006044820152606401610b0d565b61126a8b8b8b8b8b8b612d50565b60007f0000000000000000000000000000000000000000000000000000000000000000156112c7576002826020015183604001516112a89190614743565b6112b2919061478b565b6112bd906001614743565b60ff1690506112dd565b60208201516112d7906001614743565b60ff1690505b888114611346576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610b0d565b8887146113af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f7369676e617475726573206f7574206f6620726567697374726174696f6e00006044820152606401610b0d565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113f2576113f26147ad565b6002811115611403576114036147ad565b9052509050600281602001516002811115611420576114206147ad565b14801561146757506006816000015160ff16815481106114425761144261448d565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b6114cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610b0d565b50505050506114da6137ef565b6000808a8a6040516114ed9291906147dc565b604051908190038120611504918e906020016147ec565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b8981101561180e57600060018489846020811061156d5761156d61448d565b61157a91901a601b614743565b8e8e8681811061158c5761158c61448d565b905060200201358d8d878181106115a5576115a561448d565b90506020020135604051600081526020016040526040516115e2949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611604573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff80821685529296509294508401916101009004166002811115611684576116846147ad565b6002811115611695576116956147ad565b90525092506001836020015160028111156116b2576116b26147ad565b14611719576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610b0d565b8251600090879060ff16601f81106117335761173361448d565b602002015173ffffffffffffffffffffffffffffffffffffffff16146117b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610b0d565b8086846000015160ff16601f81106117cf576117cf61448d565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117fa600186614743565b94505080611807906144bc565b905061154e565b50505061181f833383858e8e612e07565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b1580156118cc57600080fd5b505afa1580156118e0573d6000803e3d6000fd5b5050505066038d7ea4c68000821115611925576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061192f610841565b9050600061197287878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061023c92505050565b905061198085858385612fd7565b98975050505050505050565b6060600c805461199b9061425d565b90506000036119d6576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610ea89061425d565b855185518560ff16601f831115611a56576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610b0d565b80600003611ac0576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610b0d565b818314611b4e576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610b0d565b611b59816003614800565b8311611bc1576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610b0d565b611bc961267c565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611c109088613144565b60055415611dc557600554600090611c2a90600190614817565b9050600060058281548110611c4157611c4161448d565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611c7b57611c7b61448d565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611cfb57611cfb61482a565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611d6457611d6461482a565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611c10915050565b60005b81515181101561222c5760006004600084600001518481518110611dee57611dee61448d565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611e3857611e386147ad565b14611e9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610b0d565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611ed057611ed061448d565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115611f7157611f716147ad565b021790555060009150611f819050565b6004600084602001518481518110611f9b57611f9b61448d565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611fe557611fe56147ad565b1461204c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610b0d565b6040805180820190915260ff82168152602081016002815250600460008460200151848151811061207f5761207f61448d565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115612120576121206147ad565b02179055505082518051600592508390811061213e5761213e61448d565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90931692909217909155820151805160069190839081106121ba576121ba61448d565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90921691909117905580612224816144bc565b915050611dc8565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff43811682029290921780855592048116929182916014916122e491849174010000000000000000000000000000000000000000900416614859565b92506101000a81548163ffffffff021916908363ffffffff1602179055506123434630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a0015161315d565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986123fa988b9891977401000000000000000000000000000000000000000090920463ffffffff16969095919491939192614876565b60405180910390a15050505050505050505050565b604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c0100000000000000000000000080830482166060850152700100000000000000000000000000000000830468ffffffffffffffffff166080850152790100000000000000000000000000000000000000000000000000830464ffffffffff1660a0808601919091527e0100000000000000000000000000000000000000000000000000000000000090930461ffff1660c08501526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08601527c01000000000000000000000000000000000000000000000000000000009004909116610100840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa15801561259d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c19190614926565b5093505092505080426125d49190614817565b836020015163ffffffff161080156125f657506000836020015163ffffffff16115b1561262457505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b60008213612661576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610b0d565b5092915050565b61267061267c565b61267981613208565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146126fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0d565b565b6126fd61267c565b600b546bffffffffffffffffffffffff1660000361272157565b600061272b610de2565b90508051600003612768576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600b54600091612787916bffffffffffffffffffffffff16614976565b905060005b82518110156128535781600a60008584815181106127ac576127ac61448d565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff1661281491906149a1565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508061284c906144bc565b905061278c565b50815161286090826149c6565b600b80546000906128809084906bffffffffffffffffffffffff16614468565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c0100000000000000000000000081048316606083015268ffffffffffffffffff700100000000000000000000000000000000820416608083015264ffffffffff79010000000000000000000000000000000000000000000000000082041660a083015261ffff7e01000000000000000000000000000000000000000000000000000000000000909104811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08501527c0100000000000000000000000000000000000000000000000000000000900490931661010080840191909152850151919291161115612a6d576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854600090700100000000000000000000000000000000900468ffffffffffffffffff1690506000612aaa8560e001513a848860800151612fd7565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612b06576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083610100015163ffffffff1642612b1f91906149ee565b905060003087604001518860a001518960c001516001612b3f9190614a01565b8a5180516020918201206101008d015160e08e0151604051612bf398979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b6040516020818303038152906040528051906020012090506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001846bffffffffffffffffffffffff168152602001886040015173ffffffffffffffffffffffffffffffffffffffff1681526020018860a0015167ffffffffffffffff1681526020018860e0015163ffffffff168152602001886080015168ffffffffffffffffff1681526020018568ffffffffffffffffff168152602001866040015163ffffffff1664ffffffffff168152602001866060015163ffffffff1664ffffffffff1681526020018363ffffffff16815250955085604051602001612d029190613e5f565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009384526007909252909120555092949350505050565b6000612d5d826020614800565b612d68856020614800565b612d74886101446149ee565b612d7e91906149ee565b612d8891906149ee565b612d939060006149ee565b9050368114612dfe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610b0d565b50505050505050565b606080808080612e1986880188614afd565b8451949950929750909550935091501580612e3657508351855114155b80612e4357508251855114155b80612e5057508151855114155b80612e5d57508051855114155b15612e94576040517f0be3632800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8551811015612fc9576000612f2e878381518110612eb757612eb761448d565b6020026020010151878481518110612ed157612ed161448d565b6020026020010151878581518110612eeb57612eeb61448d565b6020026020010151878681518110612f0557612f0561448d565b6020026020010151878781518110612f1f57612f1f61448d565b60200260200101518c516132fd565b90506000816006811115612f4457612f446147ad565b1480612f6157506001816006811115612f5f57612f5f6147ad565b145b15612fb857868281518110612f7857612f7861448d565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b50612fc2816144bc565b9050612e97565b505050505050505050505050565b600854600090790100000000000000000000000000000000000000000000000000900464ffffffffff1684101561303257600854790100000000000000000000000000000000000000000000000000900464ffffffffff1693505b6008546000906127109061304c9063ffffffff1687614800565b6130569190614bcf565b61306090866149ee565b60085490915060009087906130999063ffffffff6c01000000000000000000000000820481169168010000000000000000900416614859565b6130a39190614859565b63ffffffff16905060006130ed6000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061356d92505050565b9050600061310e826130ff8587614800565b61310991906149ee565b6136af565b9050600061312a68ffffffffffffffffff808916908a166149a1565b905061313681836149a1565b9a9950505050505050505050565b600061314e610de2565b511115610d8e57610d8e612707565b6000808a8a8a8a8a8a8a8a8a60405160200161318199989796959493929190614be3565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613287576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080848060200190518101906133149190614caf565b905060003a82610120015183610100015161332f9190614d77565b64ffffffffff166133409190614800565b905060008460ff166133886000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061356d92505050565b6133929190614bcf565b905060006133a361310983856149ee565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298d8d6133ef3a6136af565b60e08b01516134099068ffffffffffffffffff16896149a1565b338c6040518763ffffffff1660e01b815260040161342c96959493929190614d95565b60408051808303816000875af115801561344a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061346e9190614e11565b90925090506000826006811115613487576134876147ad565b14806134a4575060018260068111156134a2576134a26147ad565b145b1561355d5760008d8152600760205260408120556134c281846149a1565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0880151600b805468ffffffffffffffffff9092169390929161352e918591166149a1565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505b509b9a5050505050505050505050565b600046613579816136e3565b156135f557606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156135ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135ee9190614e44565b9392505050565b6135fe81613706565b156136a65773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e84604051806080016040528060488152602001614e8d6048913960405160200161365e929190614e5d565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016136899190613b24565b602060405180830381865afa1580156135ca573d6000803e3d6000fd5b50600092915050565b60006136dd6136bc61240f565b6136ce84670de0b6b3a7640000614800565b6136d89190614bcf565b61374d565b92915050565b600061a4b18214806136f7575062066eed82145b806136dd57505062066eee1490565b6000600a82148061371857506101a482145b80613725575062aa37dc82145b80613731575061210582145b8061373e575062014a3382145b806136dd57505062014a341490565b60006bffffffffffffffffffffffff8211156137eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b0d565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f84011261382057600080fd5b50813567ffffffffffffffff81111561383857600080fd5b60208301915083602082850101111561385057600080fd5b9250929050565b6000806020838503121561386a57600080fd5b823567ffffffffffffffff81111561388157600080fd5b61388d8582860161380e565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156138ec576138ec613899565b60405290565b604051610160810167ffffffffffffffff811182821017156138ec576138ec613899565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561395d5761395d613899565b604052919050565b63ffffffff8116811461267957600080fd5b803561117081613965565b68ffffffffffffffffff8116811461267957600080fd5b803561117081613982565b64ffffffffff8116811461267957600080fd5b8035611170816139a4565b803561ffff8116811461117057600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461117057600080fd5b60006101208284031215613a1357600080fd5b613a1b6138c8565b613a2483613977565b8152613a3260208401613977565b6020820152613a4360408401613977565b6040820152613a5460608401613977565b6060820152613a6560808401613999565b6080820152613a7660a084016139b7565b60a0820152613a8760c084016139c2565b60c0820152613a9860e084016139d4565b60e0820152610100613aab818501613977565b908201529392505050565b60005b83811015613ad1578181015183820152602001613ab9565b50506000910152565b60008151808452613af2816020860160208601613ab6565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006135ee6020830184613ada565b600082601f830112613b4857600080fd5b813567ffffffffffffffff811115613b6257613b62613899565b613b9360207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613916565b818152846020838601011115613ba857600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215613bd757600080fd5b813567ffffffffffffffff811115613bee57600080fd5b613bfa84828501613b37565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461267957600080fd5b803561117081613c02565b6bffffffffffffffffffffffff8116811461267957600080fd5b803561117081613c2f565b60008060408385031215613c6757600080fd5b8235613c7281613c02565b91506020830135613c8281613c2f565b809150509250929050565b600081518084526020808501945080840160005b83811015613cd357815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613ca1565b509495945050505050565b6020815260006135ee6020830184613c8d565b600060208284031215613d0357600080fd5b5035919050565b600060208284031215613d1c57600080fd5b813567ffffffffffffffff811115613d3357600080fd5b820161016081850312156135ee57600080fd5b805182526020810151613d71602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613d9160408401826bffffffffffffffffffffffff169052565b506060810151613db9606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613dd5608084018267ffffffffffffffff169052565b5060a0810151613ded60a084018263ffffffff169052565b5060c0810151613e0a60c084018268ffffffffffffffffff169052565b5060e0810151613e2760e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b61016081016136dd8284613d46565b60008083601f840112613e8057600080fd5b50813567ffffffffffffffff811115613e9857600080fd5b6020830191508360208260051b850101111561385057600080fd5b60008060008060008060008060e0898b031215613ecf57600080fd5b606089018a811115613ee057600080fd5b8998503567ffffffffffffffff80821115613efa57600080fd5b613f068c838d0161380e565b909950975060808b0135915080821115613f1f57600080fd5b613f2b8c838d01613e6e565b909750955060a08b0135915080821115613f4457600080fd5b50613f518b828c01613e6e565b999c989b50969995989497949560c00135949350505050565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151613fbe608084018268ffffffffffffffffff169052565b5060a0830151613fd760a084018264ffffffffff169052565b5060c0830151613fed60c084018261ffff169052565b5060e083015161401d60e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b506101008381015163ffffffff8116848301525b505092915050565b67ffffffffffffffff8116811461267957600080fd5b803561117081614039565b60008060008060006080868803121561407257600080fd5b853561407d81614039565b9450602086013567ffffffffffffffff81111561409957600080fd5b6140a58882890161380e565b90955093505060408601356140b981613965565b949793965091946060013592915050565b600067ffffffffffffffff8211156140e4576140e4613899565b5060051b60200190565b600082601f8301126140ff57600080fd5b8135602061411461410f836140ca565b613916565b82815260059290921b8401810191818101908684111561413357600080fd5b8286015b8481101561415757803561414a81613c02565b8352918301918301614137565b509695505050505050565b803560ff8116811461117057600080fd5b60008060008060008060c0878903121561418c57600080fd5b863567ffffffffffffffff808211156141a457600080fd5b6141b08a838b016140ee565b975060208901359150808211156141c657600080fd5b6141d28a838b016140ee565b96506141e060408a01614162565b955060608901359150808211156141f657600080fd5b6142028a838b01613b37565b945061421060808a0161404f565b935060a089013591508082111561422657600080fd5b5061423389828a01613b37565b9150509295509295509295565b60006020828403121561425257600080fd5b81356135ee81613c02565b600181811c9082168061427157607f821691505b6020821081036142aa577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105ec57600081815260208120601f850160051c810160208610156142d75750805b601f850160051c820191505b81811015610a88578281556001016142e3565b67ffffffffffffffff83111561430e5761430e613899565b6143228361431c835461425d565b836142b0565b6000601f841160018114614374576000851561433e5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b17835561440a565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156143c357868501358255602094850194600190920191016143a3565b50868210156143fe577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b805161117081613982565b60006020828403121561442e57600080fd5b81516135ee81613982565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff82811682821603908082111561266157612661614439565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036144ed576144ed614439565b5060010190565b6000610160823603121561450757600080fd5b61450f6138f2565b823567ffffffffffffffff81111561452657600080fd5b61453236828601613b37565b8252506020830135602082015261454b60408401613c24565b604082015261455c60608401613c49565b606082015261456d60808401613999565b608082015261457e60a0840161404f565b60a082015261458f60c0840161404f565b60c08201526145a060e08401613977565b60e08201526101006145b38185016139c2565b908201526101206145c584820161404f565b908201526101406145d7848201613c24565b9082015292915050565b6000602082840312156145f357600080fd5b81356135ee81614039565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261463357600080fd5b83018035915067ffffffffffffffff82111561464e57600080fd5b60200191503681900382131561385057600080fd5b60006020828403121561467557600080fd5b6135ee826139c2565b60006020828403121561469057600080fd5b81356135ee81613965565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061313660e0830184613d46565b60ff81811683821601908111156136dd576136dd614439565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061479e5761479e61475c565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b80820281158282048414176136dd576136dd614439565b818103818111156136dd576136dd614439565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff81811683821601908082111561266157612661614439565b600061012063ffffffff808d1684528b6020850152808b166040850152508060608401526148a68184018a613c8d565b905082810360808401526148ba8189613c8d565b905060ff871660a084015282810360c08401526148d78187613ada565b905067ffffffffffffffff851660e08401528281036101008401526148fc8185613ada565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461117057600080fd5b600080600080600060a0868803121561493e57600080fd5b6149478661490c565b945060208601519350604086015192506060860151915061496a6080870161490c565b90509295509295909350565b60006bffffffffffffffffffffffff808416806149955761499561475c565b92169190910492915050565b6bffffffffffffffffffffffff81811683821601908082111561266157612661614439565b6bffffffffffffffffffffffff81811683821602808216919082811461403157614031614439565b808201808211156136dd576136dd614439565b67ffffffffffffffff81811683821601908082111561266157612661614439565b600082601f830112614a3357600080fd5b81356020614a4361410f836140ca565b82815260059290921b84018101918181019086841115614a6257600080fd5b8286015b848110156141575780358352918301918301614a66565b600082601f830112614a8e57600080fd5b81356020614a9e61410f836140ca565b82815260059290921b84018101918181019086841115614abd57600080fd5b8286015b8481101561415757803567ffffffffffffffff811115614ae15760008081fd5b614aef8986838b0101613b37565b845250918301918301614ac1565b600080600080600060a08688031215614b1557600080fd5b853567ffffffffffffffff80821115614b2d57600080fd5b614b3989838a01614a22565b96506020880135915080821115614b4f57600080fd5b614b5b89838a01614a7d565b95506040880135915080821115614b7157600080fd5b614b7d89838a01614a7d565b94506060880135915080821115614b9357600080fd5b614b9f89838a01614a7d565b93506080880135915080821115614bb557600080fd5b50614bc288828901614a7d565b9150509295509295909350565b600082614bde57614bde61475c565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614c2a8285018b613c8d565b91508382036080850152614c3e828a613c8d565b915060ff881660a085015283820360c0850152614c5b8288613ada565b90861660e085015283810361010085015290506148fc8185613ada565b805161117081613c02565b805161117081613c2f565b805161117081614039565b805161117081613965565b8051611170816139a4565b60006101608284031215614cc257600080fd5b614cca6138f2565b82518152614cda60208401614c78565b6020820152614ceb60408401614c83565b6040820152614cfc60608401614c78565b6060820152614d0d60808401614c8e565b6080820152614d1e60a08401614c99565b60a0820152614d2f60c08401614411565b60c0820152614d4060e08401614411565b60e0820152610100614d53818501614ca4565b90820152610120614d65848201614ca4565b90820152610140613aab848201614c99565b64ffffffffff81811683821601908082111561266157612661614439565b6000610200808352614da98184018a613ada565b90508281036020840152614dbd8189613ada565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614e06905060a0830184613d46565b979650505050505050565b60008060408385031215614e2457600080fd5b825160078110614e3357600080fd5b6020840151909250613c8281613c2f565b600060208284031215614e5657600080fd5b5051919050565b60008351614e6f818460208801613ab6565b835190830190614e83818360208801613ab6565b0194935050505056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"linkToNativeFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPublicKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InconsistentReportData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoTransmittersSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouterOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReportInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustBeSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedPublicKeyChange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedRequestDataVersion\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CommitmentDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"callbackGasLimit\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"OracleResponse\",\"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\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"juelsPerGas\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1FeeShareWei\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"callbackCostJuels\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalCostJuels\",\"type\":\"uint96\"}],\"name\":\"RequestBilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"deleteCommitment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"gasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateCost\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getDONFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getThresholdPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracleWithdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"_f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"_offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"donPublicKey\",\"type\":\"bytes\"}],\"name\":\"setDONPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"thresholdPublicKey\",\"type\":\"bytes\"}],\"name\":\"setThresholdPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"availableBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"}],\"internalType\":\"structFunctionsResponse.RequestMeta\",\"name\":\"request\",\"type\":\"tuple\"}],\"name\":\"startRequest\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"transmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60c06040523480156200001157600080fd5b506040516200560838038062005608833981016040819052620000349162000474565b8282828260013380600081620000915760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c457620000c48162000140565b50505015156080526001600160a01b038116620000f457604051632530e88560e11b815260040160405180910390fd5b6001600160a01b0390811660a052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200013482620001eb565b50505050505062000633565b336001600160a01b038216036200019a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000088565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001f562000349565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160f01b026001600160f01b0364ffffffffff909216600160c81b0264ffffffffff60c81b196001600160481b03909416600160801b0293909316600160801b600160f01b031963ffffffff9586166c010000000000000000000000000263ffffffff60601b19978716680100000000000000000297909716600160401b600160801b0319998716640100000000026001600160401b0319909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e0830151610100840151909216600160e01b026001600160e01b0390921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906200033e9083906200057d565b60405180910390a150565b6200035362000355565b565b6000546001600160a01b03163314620003535760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000088565b80516001600160a01b0381168114620003c957600080fd5b919050565b60405161012081016001600160401b03811182821017156200040057634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff81168114620003c957600080fd5b80516001600160481b0381168114620003c957600080fd5b805164ffffffffff81168114620003c957600080fd5b805161ffff81168114620003c957600080fd5b80516001600160e01b0381168114620003c957600080fd5b60008060008385036101608112156200048c57600080fd5b6200049785620003b1565b935061012080601f1983011215620004ae57600080fd5b620004b8620003ce565b9150620004c86020870162000406565b8252620004d86040870162000406565b6020830152620004eb6060870162000406565b6040830152620004fe6080870162000406565b60608301526200051160a087016200041b565b60808301526200052460c0870162000433565b60a08301526200053760e0870162000449565b60c08301526101006200054c8188016200045c565b60e08401526200055e82880162000406565b90830152509150620005746101408501620003b1565b90509250925092565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151620005d060808401826001600160481b03169052565b5060a0830151620005ea60a084018264ffffffffff169052565b5060c08301516200060160c084018261ffff169052565b5060e08301516200061d60e08401826001600160e01b03169052565b506101009283015163ffffffff16919092015290565b60805160a051614f856200068360003960008181610845015281816109d301528181610ca601528181610f3a015281816110450152818161183001526133b70152600061126e0152614f856000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806381ff7048116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610560578063e4ddcea614610573578063f2fde38b1461058957600080fd5b8063c3f909d4146103b0578063d227d24514610528578063d328a91e1461055857600080fd5b8063a631571e116100bd578063a631571e1461035d578063afcb95d71461037d578063b1dc65a41461039d57600080fd5b806381ff7048146102b557806385b214cf146103225780638da5cb5b1461033557600080fd5b806366316d8d116101455780637f15e1661161011f5780637f15e16614610285578063814118341461029857806381f1b938146102ad57600080fd5b806366316d8d1461026257806379ba5097146102755780637d4807871461027d57600080fd5b8063181f5a7711610176578063181f5a77146101ba5780632a905ccc1461020c57806359b5b7ac1461022e57600080fd5b8063083a5466146101925780631112dadc146101a7575b600080fd5b6101a56101a03660046138fb565b61059c565b005b6101a56101b5366004613aa4565b6105f1565b6101f66040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e312e300000000081525081565b6040516102039190613bc8565b60405180910390f35b610214610841565b60405168ffffffffffffffffff9091168152602001610203565b61021461023c366004613c69565b50600854700100000000000000000000000000000000900468ffffffffffffffffff1690565b6101a5610270366004613cf8565b6108d7565b6101a5610a90565b6101a5610b92565b6101a56102933660046138fb565b610d92565b6102a0610de2565b6040516102039190613d82565b6101f6610e51565b6102ff60015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610203565b6101a5610330366004613d95565b610f22565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610203565b61037061036b366004613dae565b610fd4565b6040516102039190613f03565b604080516001815260006020820181905291810191909152606001610203565b6101a56103ab366004613f57565b611175565b61051b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810468ffffffffffffffffff166080830152790100000000000000000000000000000000000000000000000000810464ffffffffff1660a08301527e01000000000000000000000000000000000000000000000000000000000000900461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08301527c0100000000000000000000000000000000000000000000000000000000900490911661010082015290565b604051610203919061400e565b61053b6105363660046140fe565b61182c565b6040516bffffffffffffffffffffffff9091168152602001610203565b6101f661198c565b6101a561056e366004614217565b6119e3565b61057b61240f565b604051908152602001610203565b6101a56105973660046142e4565b612668565b6105a461267c565b60008190036105df576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105ec82848361439a565b505050565b6105f96126ff565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff64ffffffffff909216790100000000000000000000000000000000000000000000000000027fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90941670010000000000000000000000000000000002939093167fffff0000000000000000000000000000ffffffffffffffffffffffffffffffff63ffffffff9586166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9787166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e08301516101008401519092167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f51848629061083690839061400e565b60405180910390a150565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d291906144c0565b905090565b6108df612707565b806bffffffffffffffffffffffff166000036109195750336000908152600a60205260409020546bffffffffffffffffffffffff16610973565b336000908152600a60205260409020546bffffffffffffffffffffffff80831691161015610973576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906109a09084906bffffffffffffffffffffffff1661450c565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506109f57f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b158015610a7457600080fd5b505af1158015610a88573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b9a6126ff565b610ba2612707565b6000610bac610de2565b905060005b8151811015610d8e576000600a6000848481518110610bd257610bd2614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d7d576000600a6000858581518110610c3157610c31614531565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610cc87f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610cf557610cf5614531565b6020026020010151836040518363ffffffff1660e01b8152600401610d4a92919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d6457600080fd5b505af1158015610d78573d6000803e3d6000fd5b505050505b50610d8781614560565b9050610bb1565b5050565b610d9a61267c565b6000819003610dd5576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105ec82848361439a565b60606006805480602002602001604051908101604052809291908181526020018280548015610e4757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e1c575b5050505050905090565b6060600d8054610e6090614301565b9050600003610e9b576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610ea890614301565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed490614301565b8015610e475780601f10610ef657610100808354040283529160200191610e47565b820191906000526020600020905b815481529060010190602001808311610f0457509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f91576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f416906108369083815260200190565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461109c576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110ad6110a883614598565b6128b2565b90506110bf60608301604084016142e4565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff3261110d60c0870160a08801614685565b61111f610160880161014089016142e4565b61112988806146a2565b61113b6101208b016101008c01614707565b60208b01356111516101008d0160e08e01614722565b8b6040516111679998979695949392919061473f565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16040805160608101825260025480825260035460ff8082166020850152610100909104169282019290925290831461125c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f6e666967446967657374206d69736d6174636800000000000000000000006044820152606401610b0d565b61126a8b8b8b8b8b8b612d50565b60007f0000000000000000000000000000000000000000000000000000000000000000156112c7576002826020015183604001516112a891906147e7565b6112b2919061482f565b6112bd9060016147e7565b60ff1690506112dd565b60208201516112d79060016147e7565b60ff1690505b888114611346576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610b0d565b8887146113af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f7369676e617475726573206f7574206f6620726567697374726174696f6e00006044820152606401610b0d565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113f2576113f2614851565b600281111561140357611403614851565b905250905060028160200151600281111561142057611420614851565b14801561146757506006816000015160ff168154811061144257611442614531565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b6114cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610b0d565b50505050506114da613893565b6000808a8a6040516114ed929190614880565b604051908190038120611504918e90602001614890565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b8981101561180e57600060018489846020811061156d5761156d614531565b61157a91901a601b6147e7565b8e8e8681811061158c5761158c614531565b905060200201358d8d878181106115a5576115a5614531565b90506020020135604051600081526020016040526040516115e2949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611604573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff8082168552929650929450840191610100900416600281111561168457611684614851565b600281111561169557611695614851565b90525092506001836020015160028111156116b2576116b2614851565b14611719576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610b0d565b8251600090879060ff16601f811061173357611733614531565b602002015173ffffffffffffffffffffffffffffffffffffffff16146117b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610b0d565b8086846000015160ff16601f81106117cf576117cf614531565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117fa6001866147e7565b9450508061180790614560565b905061154e565b50505061181f833383858e8e612e07565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b1580156118cc57600080fd5b505afa1580156118e0573d6000803e3d6000fd5b5050505066038d7ea4c68000821115611925576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061192f610841565b9050600061197287878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061023c92505050565b905061198085858385612fd7565b98975050505050505050565b6060600c805461199b90614301565b90506000036119d6576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610ea890614301565b855185518560ff16601f831115611a56576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610b0d565b80600003611ac0576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610b0d565b818314611b4e576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610b0d565b611b598160036148a4565b8311611bc1576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610b0d565b611bc961267c565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611c109088613144565b60055415611dc557600554600090611c2a906001906148bb565b9050600060058281548110611c4157611c41614531565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611c7b57611c7b614531565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611cfb57611cfb6148ce565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611d6457611d646148ce565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611c10915050565b60005b81515181101561222c5760006004600084600001518481518110611dee57611dee614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611e3857611e38614851565b14611e9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610b0d565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611ed057611ed0614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115611f7157611f71614851565b021790555060009150611f819050565b6004600084602001518481518110611f9b57611f9b614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611fe557611fe5614851565b1461204c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610b0d565b6040805180820190915260ff82168152602081016002815250600460008460200151848151811061207f5761207f614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561212057612120614851565b02179055505082518051600592508390811061213e5761213e614531565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90931692909217909155820151805160069190839081106121ba576121ba614531565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790558061222481614560565b915050611dc8565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff43811682029290921780855592048116929182916014916122e4918491740100000000000000000000000000000000000000009004166148fd565b92506101000a81548163ffffffff021916908363ffffffff1602179055506123434630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a0015161315d565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986123fa988b9891977401000000000000000000000000000000000000000090920463ffffffff1696909591949193919261491a565b60405180910390a15050505050505050505050565b604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c0100000000000000000000000080830482166060850152700100000000000000000000000000000000830468ffffffffffffffffff166080850152790100000000000000000000000000000000000000000000000000830464ffffffffff1660a0808601919091527e0100000000000000000000000000000000000000000000000000000000000090930461ffff1660c08501526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08601527c01000000000000000000000000000000000000000000000000000000009004909116610100840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa15801561259d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c191906149ca565b5093505092505080426125d491906148bb565b836020015163ffffffff161080156125f657506000836020015163ffffffff16115b1561262457505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b60008213612661576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610b0d565b5092915050565b61267061267c565b61267981613208565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146126fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0d565b565b6126fd61267c565b600b546bffffffffffffffffffffffff1660000361272157565b600061272b610de2565b90508051600003612768576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600b54600091612787916bffffffffffffffffffffffff16614a1a565b905060005b82518110156128535781600a60008584815181106127ac576127ac614531565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff166128149190614a45565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508061284c90614560565b905061278c565b5081516128609082614a6a565b600b80546000906128809084906bffffffffffffffffffffffff1661450c565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c0100000000000000000000000081048316606083015268ffffffffffffffffff700100000000000000000000000000000000820416608083015264ffffffffff79010000000000000000000000000000000000000000000000000082041660a083015261ffff7e01000000000000000000000000000000000000000000000000000000000000909104811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08501527c0100000000000000000000000000000000000000000000000000000000900490931661010080840191909152850151919291161115612a6d576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854600090700100000000000000000000000000000000900468ffffffffffffffffff1690506000612aaa8560e001513a848860800151612fd7565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612b06576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083610100015163ffffffff1642612b1f9190614a92565b905060003087604001518860a001518960c001516001612b3f9190614aa5565b8a5180516020918201206101008d015160e08e0151604051612bf398979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b6040516020818303038152906040528051906020012090506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001846bffffffffffffffffffffffff168152602001886040015173ffffffffffffffffffffffffffffffffffffffff1681526020018860a0015167ffffffffffffffff1681526020018860e0015163ffffffff168152602001886080015168ffffffffffffffffff1681526020018568ffffffffffffffffff168152602001866040015163ffffffff1664ffffffffff168152602001866060015163ffffffff1664ffffffffff1681526020018363ffffffff16815250955085604051602001612d029190613f03565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009384526007909252909120555092949350505050565b6000612d5d8260206148a4565b612d688560206148a4565b612d7488610144614a92565b612d7e9190614a92565b612d889190614a92565b612d93906000614a92565b9050368114612dfe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610b0d565b50505050505050565b606080808080612e1986880188614ba1565b8451949950929750909550935091501580612e3657508351855114155b80612e4357508251855114155b80612e5057508151855114155b80612e5d57508051855114155b15612e94576040517f0be3632800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8551811015612fc9576000612f2e878381518110612eb757612eb7614531565b6020026020010151878481518110612ed157612ed1614531565b6020026020010151878581518110612eeb57612eeb614531565b6020026020010151878681518110612f0557612f05614531565b6020026020010151878781518110612f1f57612f1f614531565b60200260200101518c516132fd565b90506000816006811115612f4457612f44614851565b1480612f6157506001816006811115612f5f57612f5f614851565b145b15612fb857868281518110612f7857612f78614531565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b50612fc281614560565b9050612e97565b505050505050505050505050565b600854600090790100000000000000000000000000000000000000000000000000900464ffffffffff1684101561303257600854790100000000000000000000000000000000000000000000000000900464ffffffffff1693505b6008546000906127109061304c9063ffffffff16876148a4565b6130569190614c73565b6130609086614a92565b60085490915060009087906130999063ffffffff6c010000000000000000000000008204811691680100000000000000009004166148fd565b6130a391906148fd565b63ffffffff16905060006130ed6000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061361192505050565b9050600061310e826130ff85876148a4565b6131099190614a92565b613753565b9050600061312a68ffffffffffffffffff808916908a16614a45565b90506131368183614a45565b9a9950505050505050505050565b600061314e610de2565b511115610d8e57610d8e612707565b6000808a8a8a8a8a8a8a8a8a60405160200161318199989796959493929190614c87565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613287576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080848060200190518101906133149190614d53565b905060003a82610120015183610100015161332f9190614e1b565b64ffffffffff1661334091906148a4565b905060008460ff166133886000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061361192505050565b6133929190614c73565b905060006133a36131098385614a92565b905060006133b03a613753565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298e8e868b60e0015168ffffffffffffffffff168961340f9190614a45565b338d6040518763ffffffff1660e01b815260040161343296959493929190614e39565b60408051808303816000875af1158015613450573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134749190614eb5565b9092509050600082600681111561348d5761348d614851565b14806134aa575060018260068111156134a8576134a8614851565b145b156136005760008e8152600760205260408120556134c88185614a45565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0890151600b805468ffffffffffffffffff9092169390929161353491859116614a45565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508d7f90815c2e624694e8010bffad2bcefaf96af282ef1bc2ebc0042d1b89a585e0468487848b60c0015168ffffffffffffffffff168c60e0015168ffffffffffffffffff16878b6135b39190614a45565b6135bd9190614a45565b6135c79190614a45565b604080516bffffffffffffffffffffffff9586168152602081019490945291841683830152909216606082015290519081900360800190a25b509c9b505050505050505050505050565b60004661361d81613787565b1561369957606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561366e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136929190614ee8565b9392505050565b6136a2816137aa565b1561374a5773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e84604051806080016040528060488152602001614f3160489139604051602001613702929190614f01565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161372d9190613bc8565b602060405180830381865afa15801561366e573d6000803e3d6000fd5b50600092915050565b600061378161376061240f565b61377284670de0b6b3a76400006148a4565b61377c9190614c73565b6137f1565b92915050565b600061a4b182148061379b575062066eed82145b8061378157505062066eee1490565b6000600a8214806137bc57506101a482145b806137c9575062aa37dc82145b806137d5575061210582145b806137e2575062014a3382145b8061378157505062014a341490565b60006bffffffffffffffffffffffff82111561388f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b0d565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f8401126138c457600080fd5b50813567ffffffffffffffff8111156138dc57600080fd5b6020830191508360208285010111156138f457600080fd5b9250929050565b6000806020838503121561390e57600080fd5b823567ffffffffffffffff81111561392557600080fd5b613931858286016138b2565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156139905761399061393d565b60405290565b604051610160810167ffffffffffffffff811182821017156139905761399061393d565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613a0157613a0161393d565b604052919050565b63ffffffff8116811461267957600080fd5b803561117081613a09565b68ffffffffffffffffff8116811461267957600080fd5b803561117081613a26565b64ffffffffff8116811461267957600080fd5b803561117081613a48565b803561ffff8116811461117057600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461117057600080fd5b60006101208284031215613ab757600080fd5b613abf61396c565b613ac883613a1b565b8152613ad660208401613a1b565b6020820152613ae760408401613a1b565b6040820152613af860608401613a1b565b6060820152613b0960808401613a3d565b6080820152613b1a60a08401613a5b565b60a0820152613b2b60c08401613a66565b60c0820152613b3c60e08401613a78565b60e0820152610100613b4f818501613a1b565b908201529392505050565b60005b83811015613b75578181015183820152602001613b5d565b50506000910152565b60008151808452613b96816020860160208601613b5a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006136926020830184613b7e565b600082601f830112613bec57600080fd5b813567ffffffffffffffff811115613c0657613c0661393d565b613c3760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016139ba565b818152846020838601011115613c4c57600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215613c7b57600080fd5b813567ffffffffffffffff811115613c9257600080fd5b613c9e84828501613bdb565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461267957600080fd5b803561117081613ca6565b6bffffffffffffffffffffffff8116811461267957600080fd5b803561117081613cd3565b60008060408385031215613d0b57600080fd5b8235613d1681613ca6565b91506020830135613d2681613cd3565b809150509250929050565b600081518084526020808501945080840160005b83811015613d7757815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613d45565b509495945050505050565b6020815260006136926020830184613d31565b600060208284031215613da757600080fd5b5035919050565b600060208284031215613dc057600080fd5b813567ffffffffffffffff811115613dd757600080fd5b8201610160818503121561369257600080fd5b805182526020810151613e15602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613e3560408401826bffffffffffffffffffffffff169052565b506060810151613e5d606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613e79608084018267ffffffffffffffff169052565b5060a0810151613e9160a084018263ffffffff169052565b5060c0810151613eae60c084018268ffffffffffffffffff169052565b5060e0810151613ecb60e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b61016081016137818284613dea565b60008083601f840112613f2457600080fd5b50813567ffffffffffffffff811115613f3c57600080fd5b6020830191508360208260051b85010111156138f457600080fd5b60008060008060008060008060e0898b031215613f7357600080fd5b606089018a811115613f8457600080fd5b8998503567ffffffffffffffff80821115613f9e57600080fd5b613faa8c838d016138b2565b909950975060808b0135915080821115613fc357600080fd5b613fcf8c838d01613f12565b909750955060a08b0135915080821115613fe857600080fd5b50613ff58b828c01613f12565b999c989b50969995989497949560c00135949350505050565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151614062608084018268ffffffffffffffffff169052565b5060a083015161407b60a084018264ffffffffff169052565b5060c083015161409160c084018261ffff169052565b5060e08301516140c160e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b506101008381015163ffffffff8116848301525b505092915050565b67ffffffffffffffff8116811461267957600080fd5b8035611170816140dd565b60008060008060006080868803121561411657600080fd5b8535614121816140dd565b9450602086013567ffffffffffffffff81111561413d57600080fd5b614149888289016138b2565b909550935050604086013561415d81613a09565b949793965091946060013592915050565b600067ffffffffffffffff8211156141885761418861393d565b5060051b60200190565b600082601f8301126141a357600080fd5b813560206141b86141b38361416e565b6139ba565b82815260059290921b840181019181810190868411156141d757600080fd5b8286015b848110156141fb5780356141ee81613ca6565b83529183019183016141db565b509695505050505050565b803560ff8116811461117057600080fd5b60008060008060008060c0878903121561423057600080fd5b863567ffffffffffffffff8082111561424857600080fd5b6142548a838b01614192565b9750602089013591508082111561426a57600080fd5b6142768a838b01614192565b965061428460408a01614206565b9550606089013591508082111561429a57600080fd5b6142a68a838b01613bdb565b94506142b460808a016140f3565b935060a08901359150808211156142ca57600080fd5b506142d789828a01613bdb565b9150509295509295509295565b6000602082840312156142f657600080fd5b813561369281613ca6565b600181811c9082168061431557607f821691505b60208210810361434e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105ec57600081815260208120601f850160051c8101602086101561437b5750805b601f850160051c820191505b81811015610a8857828155600101614387565b67ffffffffffffffff8311156143b2576143b261393d565b6143c6836143c08354614301565b83614354565b6000601f84116001811461441857600085156143e25750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b1783556144ae565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156144675786850135825560209485019460019092019101614447565b50868210156144a2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b805161117081613a26565b6000602082840312156144d257600080fd5b815161369281613a26565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff828116828216039080821115612661576126616144dd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614591576145916144dd565b5060010190565b600061016082360312156145ab57600080fd5b6145b3613996565b823567ffffffffffffffff8111156145ca57600080fd5b6145d636828601613bdb565b825250602083013560208201526145ef60408401613cc8565b604082015261460060608401613ced565b606082015261461160808401613a3d565b608082015261462260a084016140f3565b60a082015261463360c084016140f3565b60c082015261464460e08401613a1b565b60e0820152610100614657818501613a66565b908201526101206146698482016140f3565b9082015261014061467b848201613cc8565b9082015292915050565b60006020828403121561469757600080fd5b8135613692816140dd565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126146d757600080fd5b83018035915067ffffffffffffffff8211156146f257600080fd5b6020019150368190038213156138f457600080fd5b60006020828403121561471957600080fd5b61369282613a66565b60006020828403121561473457600080fd5b813561369281613a09565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061313660e0830184613dea565b60ff8181168382160190811115613781576137816144dd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061484257614842614800565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b8082028115828204841417613781576137816144dd565b81810381811115613781576137816144dd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff818116838216019080821115612661576126616144dd565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261494a8184018a613d31565b9050828103608084015261495e8189613d31565b905060ff871660a084015282810360c084015261497b8187613b7e565b905067ffffffffffffffff851660e08401528281036101008401526149a08185613b7e565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461117057600080fd5b600080600080600060a086880312156149e257600080fd5b6149eb866149b0565b9450602086015193506040860151925060608601519150614a0e608087016149b0565b90509295509295909350565b60006bffffffffffffffffffffffff80841680614a3957614a39614800565b92169190910492915050565b6bffffffffffffffffffffffff818116838216019080821115612661576126616144dd565b6bffffffffffffffffffffffff8181168382160280821691908281146140d5576140d56144dd565b80820180821115613781576137816144dd565b67ffffffffffffffff818116838216019080821115612661576126616144dd565b600082601f830112614ad757600080fd5b81356020614ae76141b38361416e565b82815260059290921b84018101918181019086841115614b0657600080fd5b8286015b848110156141fb5780358352918301918301614b0a565b600082601f830112614b3257600080fd5b81356020614b426141b38361416e565b82815260059290921b84018101918181019086841115614b6157600080fd5b8286015b848110156141fb57803567ffffffffffffffff811115614b855760008081fd5b614b938986838b0101613bdb565b845250918301918301614b65565b600080600080600060a08688031215614bb957600080fd5b853567ffffffffffffffff80821115614bd157600080fd5b614bdd89838a01614ac6565b96506020880135915080821115614bf357600080fd5b614bff89838a01614b21565b95506040880135915080821115614c1557600080fd5b614c2189838a01614b21565b94506060880135915080821115614c3757600080fd5b614c4389838a01614b21565b93506080880135915080821115614c5957600080fd5b50614c6688828901614b21565b9150509295509295909350565b600082614c8257614c82614800565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614cce8285018b613d31565b91508382036080850152614ce2828a613d31565b915060ff881660a085015283820360c0850152614cff8288613b7e565b90861660e085015283810361010085015290506149a08185613b7e565b805161117081613ca6565b805161117081613cd3565b8051611170816140dd565b805161117081613a09565b805161117081613a48565b60006101608284031215614d6657600080fd5b614d6e613996565b82518152614d7e60208401614d1c565b6020820152614d8f60408401614d27565b6040820152614da060608401614d1c565b6060820152614db160808401614d32565b6080820152614dc260a08401614d3d565b60a0820152614dd360c084016144b5565b60c0820152614de460e084016144b5565b60e0820152610100614df7818501614d48565b90820152610120614e09848201614d48565b90820152610140613b4f848201614d3d565b64ffffffffff818116838216019080821115612661576126616144dd565b6000610200808352614e4d8184018a613b7e565b90508281036020840152614e618189613b7e565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614eaa905060a0830184613dea565b979650505050505050565b60008060408385031215614ec857600080fd5b825160078110614ed757600080fd5b6020840151909250613d2681613cd3565b600060208284031215614efa57600080fd5b5051919050565b60008351614f13818460208801613b5a565b835190830190614f27818360208801613b5a565b0194935050505056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", } var FunctionsCoordinatorABI = FunctionsCoordinatorMetaData.ABI @@ -1528,6 +1528,137 @@ func (_FunctionsCoordinator *FunctionsCoordinatorFilterer) ParseOwnershipTransfe return event, nil } +type FunctionsCoordinatorRequestBilledIterator struct { + Event *FunctionsCoordinatorRequestBilled + + contract *bind.BoundContract + event string + + logs chan types.Log + sub ethereum.Subscription + done bool + fail error +} + +func (it *FunctionsCoordinatorRequestBilledIterator) Next() bool { + + if it.fail != nil { + return false + } + + if it.done { + select { + case log := <-it.logs: + it.Event = new(FunctionsCoordinatorRequestBilled) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + + select { + case log := <-it.logs: + it.Event = new(FunctionsCoordinatorRequestBilled) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +func (it *FunctionsCoordinatorRequestBilledIterator) Error() error { + return it.fail +} + +func (it *FunctionsCoordinatorRequestBilledIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +type FunctionsCoordinatorRequestBilled struct { + RequestId [32]byte + JuelsPerGas *big.Int + L1FeeShareWei *big.Int + CallbackCostJuels *big.Int + TotalCostJuels *big.Int + Raw types.Log +} + +func (_FunctionsCoordinator *FunctionsCoordinatorFilterer) FilterRequestBilled(opts *bind.FilterOpts, requestId [][32]byte) (*FunctionsCoordinatorRequestBilledIterator, error) { + + var requestIdRule []interface{} + for _, requestIdItem := range requestId { + requestIdRule = append(requestIdRule, requestIdItem) + } + + logs, sub, err := _FunctionsCoordinator.contract.FilterLogs(opts, "RequestBilled", requestIdRule) + if err != nil { + return nil, err + } + return &FunctionsCoordinatorRequestBilledIterator{contract: _FunctionsCoordinator.contract, event: "RequestBilled", logs: logs, sub: sub}, nil +} + +func (_FunctionsCoordinator *FunctionsCoordinatorFilterer) WatchRequestBilled(opts *bind.WatchOpts, sink chan<- *FunctionsCoordinatorRequestBilled, requestId [][32]byte) (event.Subscription, error) { + + var requestIdRule []interface{} + for _, requestIdItem := range requestId { + requestIdRule = append(requestIdRule, requestIdItem) + } + + logs, sub, err := _FunctionsCoordinator.contract.WatchLogs(opts, "RequestBilled", requestIdRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + + event := new(FunctionsCoordinatorRequestBilled) + if err := _FunctionsCoordinator.contract.UnpackLog(event, "RequestBilled", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +func (_FunctionsCoordinator *FunctionsCoordinatorFilterer) ParseRequestBilled(log types.Log) (*FunctionsCoordinatorRequestBilled, error) { + event := new(FunctionsCoordinatorRequestBilled) + if err := _FunctionsCoordinator.contract.UnpackLog(event, "RequestBilled", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} + type FunctionsCoordinatorTransmittedIterator struct { Event *FunctionsCoordinatorTransmitted @@ -1673,6 +1804,8 @@ func (_FunctionsCoordinator *FunctionsCoordinator) ParseLog(log types.Log) (gene return _FunctionsCoordinator.ParseOwnershipTransferRequested(log) case _FunctionsCoordinator.abi.Events["OwnershipTransferred"].ID: return _FunctionsCoordinator.ParseOwnershipTransferred(log) + case _FunctionsCoordinator.abi.Events["RequestBilled"].ID: + return _FunctionsCoordinator.ParseRequestBilled(log) case _FunctionsCoordinator.abi.Events["Transmitted"].ID: return _FunctionsCoordinator.ParseTransmitted(log) @@ -1709,6 +1842,10 @@ func (FunctionsCoordinatorOwnershipTransferred) Topic() common.Hash { return common.HexToHash("0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0") } +func (FunctionsCoordinatorRequestBilled) Topic() common.Hash { + return common.HexToHash("0x90815c2e624694e8010bffad2bcefaf96af282ef1bc2ebc0042d1b89a585e046") +} + func (FunctionsCoordinatorTransmitted) Topic() common.Hash { return common.HexToHash("0xb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62") } @@ -1810,6 +1947,12 @@ type FunctionsCoordinatorInterface interface { ParseOwnershipTransferred(log types.Log) (*FunctionsCoordinatorOwnershipTransferred, error) + FilterRequestBilled(opts *bind.FilterOpts, requestId [][32]byte) (*FunctionsCoordinatorRequestBilledIterator, error) + + WatchRequestBilled(opts *bind.WatchOpts, sink chan<- *FunctionsCoordinatorRequestBilled, requestId [][32]byte) (event.Subscription, error) + + ParseRequestBilled(log types.Log) (*FunctionsCoordinatorRequestBilled, error) + FilterTransmitted(opts *bind.FilterOpts) (*FunctionsCoordinatorTransmittedIterator, error) WatchTransmitted(opts *bind.WatchOpts, sink chan<- *FunctionsCoordinatorTransmitted) (event.Subscription, error) diff --git a/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 3543116d21d..41524c3a829 100644 --- a/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -4,7 +4,7 @@ functions_allow_list: ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServ functions_billing_registry_events_mock: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistryEventsMock.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistryEventsMock.bin 50deeb883bd9c3729702be335c0388f9d8553bab4be5e26ecacac496a89e2b77 functions_client: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClient.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClient.bin 2368f537a04489c720a46733f8596c4fc88a31062ecfa966d05f25dd98608aca functions_client_example: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClientExample.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClientExample.bin abf32e69f268f40e8530eb8d8e96bf310b798a4c0049a58022d9d2fb527b601b -functions_coordinator: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.bin 948c04942910f308942fdde460317f9ec038b6b702b018471ce6157a14a09072 +functions_coordinator: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.bin 96416d5be2ae4625395567397da88f71b215005cf8ad71a1cdaa56e6b5e16908 functions_load_test_client: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsLoadTestClient.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsLoadTestClient.bin c8dbbd5ebb34435800d6674700068837c3a252db60046a14b0e61e829db517de functions_oracle_events_mock: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracleEventsMock.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracleEventsMock.bin 3ca70f966f8fe751987f0ccb50bebb6aa5be77e4a9f835d1ae99e0e9bfb7d52c functions_router: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.bin 9dedd3a36043605fd9bedf821e7ec5b4281a5c7ae2e4a1955f37aff8ba13519f From 22d77f95e1355986120580576632e9880ce36ffe Mon Sep 17 00:00:00 2001 From: Justin Kaseman Date: Thu, 9 Nov 2023 19:53:33 -0500 Subject: [PATCH 6/7] FUN-958 - Golf golf changes, store repeated .length as a variable (#11251) --- .../gas-snapshots/functions.gas-snapshot | 52 +++++++++---------- .../functions/dev/v1_X/FunctionsBilling.sol | 9 ++-- .../dev/v1_X/FunctionsCoordinator.sol | 15 +++--- .../functions_coordinator.go | 2 +- ...rapper-dependency-versions-do-not-edit.txt | 2 +- 5 files changed, 41 insertions(+), 39 deletions(-) diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index af95b75df10..d15666f8857 100644 --- a/contracts/gas-snapshots/functions.gas-snapshot +++ b/contracts/gas-snapshots/functions.gas-snapshot @@ -1,12 +1,12 @@ -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 14534216) -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14534194) -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14534210) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14545630) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14545607) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14545579) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14545530) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14545519) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14545563) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 14534206) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14534184) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14534200) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14545620) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14545597) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14545569) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14545520) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14545509) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14545553) FunctionsBilling_Constructor:test_Constructor_Success() (gas: 14812) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_RevertIfNotRouter() (gas: 13282) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_Success() (gas: 15897) @@ -17,20 +17,20 @@ FunctionsBilling_GetAdminFee:test_GetAdminFee_Success() (gas: 18226) FunctionsBilling_GetConfig:test_GetConfig_Success() (gas: 23671) FunctionsBilling_GetDONFee:test_GetDONFee_Success() (gas: 15792) FunctionsBilling_GetWeiPerUnitLink:test_GetWeiPerUnitLink_Success() (gas: 31773) -FunctionsBilling_OracleWithdraw:test_OracleWithdraw_RevertIfInsufficientBalance() (gas: 70138) -FunctionsBilling_OracleWithdraw:test_OracleWithdraw_RevertWithNoBalance() (gas: 106295) -FunctionsBilling_OracleWithdraw:test_OracleWithdraw_SuccessTransmitterWithBalanceNoAmountGiven() (gas: 140174) -FunctionsBilling_OracleWithdraw:test_OracleWithdraw_SuccessTransmitterWithBalanceValidAmountGiven() (gas: 142502) +FunctionsBilling_OracleWithdraw:test_OracleWithdraw_RevertIfInsufficientBalance() (gas: 70128) +FunctionsBilling_OracleWithdraw:test_OracleWithdraw_RevertWithNoBalance() (gas: 106285) +FunctionsBilling_OracleWithdraw:test_OracleWithdraw_SuccessTransmitterWithBalanceNoAmountGiven() (gas: 140164) +FunctionsBilling_OracleWithdraw:test_OracleWithdraw_SuccessTransmitterWithBalanceValidAmountGiven() (gas: 142492) FunctionsBilling_OracleWithdrawAll:test_OracleWithdrawAll_RevertIfNotOwner() (gas: 13296) FunctionsBilling_OracleWithdrawAll:test_OracleWithdrawAll_SuccessPaysTransmittersWithBalance() (gas: 147278) FunctionsBilling_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 18974) FunctionsBilling_UpdateConfig:test_UpdateConfig_Success() (gas: 38251) -FunctionsBilling__DisperseFeePool:test__DisperseFeePool_RevertIfNotSet() (gas: 8801) +FunctionsBilling__DisperseFeePool:test__DisperseFeePool_RevertIfNotSet() (gas: 8810) FunctionsBilling__FulfillAndBill:test__FulfillAndBill_RevertIfInvalidCommitment() (gas: 13302) FunctionsBilling__FulfillAndBill:test__FulfillAndBill_Success() (gas: 180763) FunctionsClient_Constructor:test_Constructor_Success() (gas: 7573) -FunctionsClient_FulfillRequest:test_FulfillRequest_MaximumGas() (gas: 504364) -FunctionsClient_FulfillRequest:test_FulfillRequest_MinimumGas() (gas: 205568) +FunctionsClient_FulfillRequest:test_FulfillRequest_MaximumGas() (gas: 504354) +FunctionsClient_FulfillRequest:test_FulfillRequest_MinimumGas() (gas: 205558) FunctionsClient_HandleOracleFulfillment:test_HandleOracleFulfillment_RevertIfNotRouter() (gas: 14623) FunctionsClient_HandleOracleFulfillment:test_HandleOracleFulfillment_Success() (gas: 22923) FunctionsClient__SendRequest:test__SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 55059) @@ -51,17 +51,17 @@ FunctionsRequest_DEFAULT_BUFFER_SIZE:test_DEFAULT_BUFFER_SIZE() (gas: 246) FunctionsRequest_EncodeCBOR:test_EncodeCBOR_Success() (gas: 223) FunctionsRequest_REQUEST_DATA_VERSION:test_REQUEST_DATA_VERSION() (gas: 225) FunctionsRouter_Constructor:test_Constructor_Success() (gas: 12007) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 174037) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 164368) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 174027) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 164358) FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidCommitment() (gas: 38115) FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidRequestId() (gas: 35238) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 182513) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 182503) FunctionsRouter_Fulfill:test_Fulfill_RevertIfNotCommittedCoordinator() (gas: 28086) -FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 158055) -FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 327615) -FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 341236) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2516517) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 546996) +FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 158046) +FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 327605) +FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 341226) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2516507) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 546986) FunctionsRouter_GetAdminFee:test_GetAdminFee_Success() (gas: 17983) FunctionsRouter_GetAllowListId:test_GetAllowListId_Success() (gas: 12904) FunctionsRouter_GetConfig:test_GetConfig_Success() (gas: 37159) @@ -144,8 +144,8 @@ FunctionsSubscriptions_GetTotalBalance:test_GetTotalBalance_Success() (gas: 1501 FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata(uint96) (runs: 256, μ: 43685, ~: 45548) FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96) (runs: 256, μ: 46197, ~: 48060) FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink(uint96) (runs: 256, μ: 14295, ~: 14295) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused(uint96) (runs: 256, μ: 51089, ~: 53040) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 86057, ~: 89604) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused(uint96) (runs: 256, μ: 51177, ~: 53040) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 85879, ~: 89604) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfAmountMoreThanBalance() (gas: 20745) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfBalanceInvariant() (gas: 189) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfNoAmount() (gas: 15638) diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol index bd13a3a5a1a..e4b6fe7d90c 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol @@ -374,15 +374,16 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling { // All transmitters are assumed to also be observers // Pay out the DON fee to all transmitters address[] memory transmitters = _getTransmitters(); - if (transmitters.length == 0) { + uint256 numberOfTransmitters = transmitters.length; + if (numberOfTransmitters == 0) { revert NoTransmittersSet(); } - uint96 feePoolShare = s_feePool / uint96(transmitters.length); + uint96 feePoolShare = s_feePool / uint96(numberOfTransmitters); // Bounded by "maxNumOracles" on OCR2Abstract.sol - for (uint256 i = 0; i < transmitters.length; ++i) { + for (uint256 i = 0; i < numberOfTransmitters; ++i) { s_withdrawableTokens[transmitters[i]] += feePoolShare; } - s_feePool -= feePoolShare * uint96(transmitters.length); + s_feePool -= feePoolShare * uint96(numberOfTransmitters); } // Overriden in FunctionsCoordinator.sol diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol index 2caab41c746..3ee4931e97c 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol @@ -142,19 +142,20 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli report, (bytes32[], bytes[], bytes[], bytes[], bytes[]) ); + uint256 numberOfFulfillments = uint8(requestIds.length); if ( - requestIds.length == 0 || - requestIds.length != results.length || - requestIds.length != errors.length || - requestIds.length != onchainMetadata.length || - requestIds.length != offchainMetadata.length + numberOfFulfillments == 0 || + numberOfFulfillments != results.length || + numberOfFulfillments != errors.length || + numberOfFulfillments != onchainMetadata.length || + numberOfFulfillments != offchainMetadata.length ) { revert ReportInvalid(); } // Bounded by "MaxRequestBatchSize" on the Job's ReportingPluginConfig - for (uint256 i = 0; i < requestIds.length; ++i) { + for (uint256 i = 0; i < numberOfFulfillments; ++i) { FunctionsResponse.FulfillResult result = FunctionsResponse.FulfillResult( _fulfillAndBill( requestIds[i], @@ -162,7 +163,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli errors[i], onchainMetadata[i], offchainMetadata[i], - uint8(requestIds.length) // will not exceed "MaxRequestBatchSize" on the Job's ReportingPluginConfig + uint8(numberOfFulfillments) // will not exceed "MaxRequestBatchSize" on the Job's ReportingPluginConfig ) ); diff --git a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go index 397ea3d18bb..917107524bf 100644 --- a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go +++ b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go @@ -72,7 +72,7 @@ type FunctionsResponseRequestMeta struct { var FunctionsCoordinatorMetaData = &bind.MetaData{ ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"linkToNativeFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPublicKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InconsistentReportData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoTransmittersSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouterOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReportInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustBeSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedPublicKeyChange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedRequestDataVersion\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CommitmentDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"callbackGasLimit\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"OracleResponse\",\"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\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"juelsPerGas\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1FeeShareWei\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"callbackCostJuels\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalCostJuels\",\"type\":\"uint96\"}],\"name\":\"RequestBilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"deleteCommitment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"gasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateCost\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getDONFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getThresholdPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracleWithdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"_f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"_offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"donPublicKey\",\"type\":\"bytes\"}],\"name\":\"setDONPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"thresholdPublicKey\",\"type\":\"bytes\"}],\"name\":\"setThresholdPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"availableBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"}],\"internalType\":\"structFunctionsResponse.RequestMeta\",\"name\":\"request\",\"type\":\"tuple\"}],\"name\":\"startRequest\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"transmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60c06040523480156200001157600080fd5b506040516200560838038062005608833981016040819052620000349162000474565b8282828260013380600081620000915760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c457620000c48162000140565b50505015156080526001600160a01b038116620000f457604051632530e88560e11b815260040160405180910390fd5b6001600160a01b0390811660a052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200013482620001eb565b50505050505062000633565b336001600160a01b038216036200019a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000088565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001f562000349565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160f01b026001600160f01b0364ffffffffff909216600160c81b0264ffffffffff60c81b196001600160481b03909416600160801b0293909316600160801b600160f01b031963ffffffff9586166c010000000000000000000000000263ffffffff60601b19978716680100000000000000000297909716600160401b600160801b0319998716640100000000026001600160401b0319909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e0830151610100840151909216600160e01b026001600160e01b0390921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906200033e9083906200057d565b60405180910390a150565b6200035362000355565b565b6000546001600160a01b03163314620003535760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000088565b80516001600160a01b0381168114620003c957600080fd5b919050565b60405161012081016001600160401b03811182821017156200040057634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff81168114620003c957600080fd5b80516001600160481b0381168114620003c957600080fd5b805164ffffffffff81168114620003c957600080fd5b805161ffff81168114620003c957600080fd5b80516001600160e01b0381168114620003c957600080fd5b60008060008385036101608112156200048c57600080fd5b6200049785620003b1565b935061012080601f1983011215620004ae57600080fd5b620004b8620003ce565b9150620004c86020870162000406565b8252620004d86040870162000406565b6020830152620004eb6060870162000406565b6040830152620004fe6080870162000406565b60608301526200051160a087016200041b565b60808301526200052460c0870162000433565b60a08301526200053760e0870162000449565b60c08301526101006200054c8188016200045c565b60e08401526200055e82880162000406565b90830152509150620005746101408501620003b1565b90509250925092565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151620005d060808401826001600160481b03169052565b5060a0830151620005ea60a084018264ffffffffff169052565b5060c08301516200060160c084018261ffff169052565b5060e08301516200061d60e08401826001600160e01b03169052565b506101009283015163ffffffff16919092015290565b60805160a051614f856200068360003960008181610845015281816109d301528181610ca601528181610f3a015281816110450152818161183001526133b70152600061126e0152614f856000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806381ff7048116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610560578063e4ddcea614610573578063f2fde38b1461058957600080fd5b8063c3f909d4146103b0578063d227d24514610528578063d328a91e1461055857600080fd5b8063a631571e116100bd578063a631571e1461035d578063afcb95d71461037d578063b1dc65a41461039d57600080fd5b806381ff7048146102b557806385b214cf146103225780638da5cb5b1461033557600080fd5b806366316d8d116101455780637f15e1661161011f5780637f15e16614610285578063814118341461029857806381f1b938146102ad57600080fd5b806366316d8d1461026257806379ba5097146102755780637d4807871461027d57600080fd5b8063181f5a7711610176578063181f5a77146101ba5780632a905ccc1461020c57806359b5b7ac1461022e57600080fd5b8063083a5466146101925780631112dadc146101a7575b600080fd5b6101a56101a03660046138fb565b61059c565b005b6101a56101b5366004613aa4565b6105f1565b6101f66040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e312e300000000081525081565b6040516102039190613bc8565b60405180910390f35b610214610841565b60405168ffffffffffffffffff9091168152602001610203565b61021461023c366004613c69565b50600854700100000000000000000000000000000000900468ffffffffffffffffff1690565b6101a5610270366004613cf8565b6108d7565b6101a5610a90565b6101a5610b92565b6101a56102933660046138fb565b610d92565b6102a0610de2565b6040516102039190613d82565b6101f6610e51565b6102ff60015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610203565b6101a5610330366004613d95565b610f22565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610203565b61037061036b366004613dae565b610fd4565b6040516102039190613f03565b604080516001815260006020820181905291810191909152606001610203565b6101a56103ab366004613f57565b611175565b61051b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810468ffffffffffffffffff166080830152790100000000000000000000000000000000000000000000000000810464ffffffffff1660a08301527e01000000000000000000000000000000000000000000000000000000000000900461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08301527c0100000000000000000000000000000000000000000000000000000000900490911661010082015290565b604051610203919061400e565b61053b6105363660046140fe565b61182c565b6040516bffffffffffffffffffffffff9091168152602001610203565b6101f661198c565b6101a561056e366004614217565b6119e3565b61057b61240f565b604051908152602001610203565b6101a56105973660046142e4565b612668565b6105a461267c565b60008190036105df576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105ec82848361439a565b505050565b6105f96126ff565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff64ffffffffff909216790100000000000000000000000000000000000000000000000000027fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90941670010000000000000000000000000000000002939093167fffff0000000000000000000000000000ffffffffffffffffffffffffffffffff63ffffffff9586166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9787166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e08301516101008401519092167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f51848629061083690839061400e565b60405180910390a150565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d291906144c0565b905090565b6108df612707565b806bffffffffffffffffffffffff166000036109195750336000908152600a60205260409020546bffffffffffffffffffffffff16610973565b336000908152600a60205260409020546bffffffffffffffffffffffff80831691161015610973576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906109a09084906bffffffffffffffffffffffff1661450c565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506109f57f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b158015610a7457600080fd5b505af1158015610a88573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b9a6126ff565b610ba2612707565b6000610bac610de2565b905060005b8151811015610d8e576000600a6000848481518110610bd257610bd2614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d7d576000600a6000858581518110610c3157610c31614531565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610cc87f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610cf557610cf5614531565b6020026020010151836040518363ffffffff1660e01b8152600401610d4a92919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d6457600080fd5b505af1158015610d78573d6000803e3d6000fd5b505050505b50610d8781614560565b9050610bb1565b5050565b610d9a61267c565b6000819003610dd5576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105ec82848361439a565b60606006805480602002602001604051908101604052809291908181526020018280548015610e4757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e1c575b5050505050905090565b6060600d8054610e6090614301565b9050600003610e9b576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610ea890614301565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed490614301565b8015610e475780601f10610ef657610100808354040283529160200191610e47565b820191906000526020600020905b815481529060010190602001808311610f0457509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f91576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f416906108369083815260200190565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461109c576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110ad6110a883614598565b6128b2565b90506110bf60608301604084016142e4565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff3261110d60c0870160a08801614685565b61111f610160880161014089016142e4565b61112988806146a2565b61113b6101208b016101008c01614707565b60208b01356111516101008d0160e08e01614722565b8b6040516111679998979695949392919061473f565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16040805160608101825260025480825260035460ff8082166020850152610100909104169282019290925290831461125c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f6e666967446967657374206d69736d6174636800000000000000000000006044820152606401610b0d565b61126a8b8b8b8b8b8b612d50565b60007f0000000000000000000000000000000000000000000000000000000000000000156112c7576002826020015183604001516112a891906147e7565b6112b2919061482f565b6112bd9060016147e7565b60ff1690506112dd565b60208201516112d79060016147e7565b60ff1690505b888114611346576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610b0d565b8887146113af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f7369676e617475726573206f7574206f6620726567697374726174696f6e00006044820152606401610b0d565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113f2576113f2614851565b600281111561140357611403614851565b905250905060028160200151600281111561142057611420614851565b14801561146757506006816000015160ff168154811061144257611442614531565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b6114cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610b0d565b50505050506114da613893565b6000808a8a6040516114ed929190614880565b604051908190038120611504918e90602001614890565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b8981101561180e57600060018489846020811061156d5761156d614531565b61157a91901a601b6147e7565b8e8e8681811061158c5761158c614531565b905060200201358d8d878181106115a5576115a5614531565b90506020020135604051600081526020016040526040516115e2949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611604573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff8082168552929650929450840191610100900416600281111561168457611684614851565b600281111561169557611695614851565b90525092506001836020015160028111156116b2576116b2614851565b14611719576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610b0d565b8251600090879060ff16601f811061173357611733614531565b602002015173ffffffffffffffffffffffffffffffffffffffff16146117b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610b0d565b8086846000015160ff16601f81106117cf576117cf614531565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117fa6001866147e7565b9450508061180790614560565b905061154e565b50505061181f833383858e8e612e07565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b1580156118cc57600080fd5b505afa1580156118e0573d6000803e3d6000fd5b5050505066038d7ea4c68000821115611925576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061192f610841565b9050600061197287878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061023c92505050565b905061198085858385612fd7565b98975050505050505050565b6060600c805461199b90614301565b90506000036119d6576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610ea890614301565b855185518560ff16601f831115611a56576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610b0d565b80600003611ac0576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610b0d565b818314611b4e576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610b0d565b611b598160036148a4565b8311611bc1576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610b0d565b611bc961267c565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611c109088613144565b60055415611dc557600554600090611c2a906001906148bb565b9050600060058281548110611c4157611c41614531565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611c7b57611c7b614531565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611cfb57611cfb6148ce565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611d6457611d646148ce565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611c10915050565b60005b81515181101561222c5760006004600084600001518481518110611dee57611dee614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611e3857611e38614851565b14611e9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610b0d565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611ed057611ed0614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115611f7157611f71614851565b021790555060009150611f819050565b6004600084602001518481518110611f9b57611f9b614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611fe557611fe5614851565b1461204c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610b0d565b6040805180820190915260ff82168152602081016002815250600460008460200151848151811061207f5761207f614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561212057612120614851565b02179055505082518051600592508390811061213e5761213e614531565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90931692909217909155820151805160069190839081106121ba576121ba614531565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790558061222481614560565b915050611dc8565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff43811682029290921780855592048116929182916014916122e4918491740100000000000000000000000000000000000000009004166148fd565b92506101000a81548163ffffffff021916908363ffffffff1602179055506123434630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a0015161315d565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986123fa988b9891977401000000000000000000000000000000000000000090920463ffffffff1696909591949193919261491a565b60405180910390a15050505050505050505050565b604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c0100000000000000000000000080830482166060850152700100000000000000000000000000000000830468ffffffffffffffffff166080850152790100000000000000000000000000000000000000000000000000830464ffffffffff1660a0808601919091527e0100000000000000000000000000000000000000000000000000000000000090930461ffff1660c08501526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08601527c01000000000000000000000000000000000000000000000000000000009004909116610100840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa15801561259d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c191906149ca565b5093505092505080426125d491906148bb565b836020015163ffffffff161080156125f657506000836020015163ffffffff16115b1561262457505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b60008213612661576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610b0d565b5092915050565b61267061267c565b61267981613208565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146126fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0d565b565b6126fd61267c565b600b546bffffffffffffffffffffffff1660000361272157565b600061272b610de2565b90508051600003612768576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8051600b54600091612787916bffffffffffffffffffffffff16614a1a565b905060005b82518110156128535781600a60008584815181106127ac576127ac614531565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff166128149190614a45565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508061284c90614560565b905061278c565b5081516128609082614a6a565b600b80546000906128809084906bffffffffffffffffffffffff1661450c565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c0100000000000000000000000081048316606083015268ffffffffffffffffff700100000000000000000000000000000000820416608083015264ffffffffff79010000000000000000000000000000000000000000000000000082041660a083015261ffff7e01000000000000000000000000000000000000000000000000000000000000909104811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08501527c0100000000000000000000000000000000000000000000000000000000900490931661010080840191909152850151919291161115612a6d576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854600090700100000000000000000000000000000000900468ffffffffffffffffff1690506000612aaa8560e001513a848860800151612fd7565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612b06576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083610100015163ffffffff1642612b1f9190614a92565b905060003087604001518860a001518960c001516001612b3f9190614aa5565b8a5180516020918201206101008d015160e08e0151604051612bf398979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b6040516020818303038152906040528051906020012090506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001846bffffffffffffffffffffffff168152602001886040015173ffffffffffffffffffffffffffffffffffffffff1681526020018860a0015167ffffffffffffffff1681526020018860e0015163ffffffff168152602001886080015168ffffffffffffffffff1681526020018568ffffffffffffffffff168152602001866040015163ffffffff1664ffffffffff168152602001866060015163ffffffff1664ffffffffff1681526020018363ffffffff16815250955085604051602001612d029190613f03565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009384526007909252909120555092949350505050565b6000612d5d8260206148a4565b612d688560206148a4565b612d7488610144614a92565b612d7e9190614a92565b612d889190614a92565b612d93906000614a92565b9050368114612dfe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610b0d565b50505050505050565b606080808080612e1986880188614ba1565b8451949950929750909550935091501580612e3657508351855114155b80612e4357508251855114155b80612e5057508151855114155b80612e5d57508051855114155b15612e94576040517f0be3632800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8551811015612fc9576000612f2e878381518110612eb757612eb7614531565b6020026020010151878481518110612ed157612ed1614531565b6020026020010151878581518110612eeb57612eeb614531565b6020026020010151878681518110612f0557612f05614531565b6020026020010151878781518110612f1f57612f1f614531565b60200260200101518c516132fd565b90506000816006811115612f4457612f44614851565b1480612f6157506001816006811115612f5f57612f5f614851565b145b15612fb857868281518110612f7857612f78614531565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b50612fc281614560565b9050612e97565b505050505050505050505050565b600854600090790100000000000000000000000000000000000000000000000000900464ffffffffff1684101561303257600854790100000000000000000000000000000000000000000000000000900464ffffffffff1693505b6008546000906127109061304c9063ffffffff16876148a4565b6130569190614c73565b6130609086614a92565b60085490915060009087906130999063ffffffff6c010000000000000000000000008204811691680100000000000000009004166148fd565b6130a391906148fd565b63ffffffff16905060006130ed6000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061361192505050565b9050600061310e826130ff85876148a4565b6131099190614a92565b613753565b9050600061312a68ffffffffffffffffff808916908a16614a45565b90506131368183614a45565b9a9950505050505050505050565b600061314e610de2565b511115610d8e57610d8e612707565b6000808a8a8a8a8a8a8a8a8a60405160200161318199989796959493929190614c87565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613287576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080848060200190518101906133149190614d53565b905060003a82610120015183610100015161332f9190614e1b565b64ffffffffff1661334091906148a4565b905060008460ff166133886000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061361192505050565b6133929190614c73565b905060006133a36131098385614a92565b905060006133b03a613753565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298e8e868b60e0015168ffffffffffffffffff168961340f9190614a45565b338d6040518763ffffffff1660e01b815260040161343296959493929190614e39565b60408051808303816000875af1158015613450573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134749190614eb5565b9092509050600082600681111561348d5761348d614851565b14806134aa575060018260068111156134a8576134a8614851565b145b156136005760008e8152600760205260408120556134c88185614a45565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0890151600b805468ffffffffffffffffff9092169390929161353491859116614a45565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508d7f90815c2e624694e8010bffad2bcefaf96af282ef1bc2ebc0042d1b89a585e0468487848b60c0015168ffffffffffffffffff168c60e0015168ffffffffffffffffff16878b6135b39190614a45565b6135bd9190614a45565b6135c79190614a45565b604080516bffffffffffffffffffffffff9586168152602081019490945291841683830152909216606082015290519081900360800190a25b509c9b505050505050505050505050565b60004661361d81613787565b1561369957606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561366e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136929190614ee8565b9392505050565b6136a2816137aa565b1561374a5773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e84604051806080016040528060488152602001614f3160489139604051602001613702929190614f01565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161372d9190613bc8565b602060405180830381865afa15801561366e573d6000803e3d6000fd5b50600092915050565b600061378161376061240f565b61377284670de0b6b3a76400006148a4565b61377c9190614c73565b6137f1565b92915050565b600061a4b182148061379b575062066eed82145b8061378157505062066eee1490565b6000600a8214806137bc57506101a482145b806137c9575062aa37dc82145b806137d5575061210582145b806137e2575062014a3382145b8061378157505062014a341490565b60006bffffffffffffffffffffffff82111561388f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b0d565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f8401126138c457600080fd5b50813567ffffffffffffffff8111156138dc57600080fd5b6020830191508360208285010111156138f457600080fd5b9250929050565b6000806020838503121561390e57600080fd5b823567ffffffffffffffff81111561392557600080fd5b613931858286016138b2565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156139905761399061393d565b60405290565b604051610160810167ffffffffffffffff811182821017156139905761399061393d565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613a0157613a0161393d565b604052919050565b63ffffffff8116811461267957600080fd5b803561117081613a09565b68ffffffffffffffffff8116811461267957600080fd5b803561117081613a26565b64ffffffffff8116811461267957600080fd5b803561117081613a48565b803561ffff8116811461117057600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461117057600080fd5b60006101208284031215613ab757600080fd5b613abf61396c565b613ac883613a1b565b8152613ad660208401613a1b565b6020820152613ae760408401613a1b565b6040820152613af860608401613a1b565b6060820152613b0960808401613a3d565b6080820152613b1a60a08401613a5b565b60a0820152613b2b60c08401613a66565b60c0820152613b3c60e08401613a78565b60e0820152610100613b4f818501613a1b565b908201529392505050565b60005b83811015613b75578181015183820152602001613b5d565b50506000910152565b60008151808452613b96816020860160208601613b5a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006136926020830184613b7e565b600082601f830112613bec57600080fd5b813567ffffffffffffffff811115613c0657613c0661393d565b613c3760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016139ba565b818152846020838601011115613c4c57600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215613c7b57600080fd5b813567ffffffffffffffff811115613c9257600080fd5b613c9e84828501613bdb565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461267957600080fd5b803561117081613ca6565b6bffffffffffffffffffffffff8116811461267957600080fd5b803561117081613cd3565b60008060408385031215613d0b57600080fd5b8235613d1681613ca6565b91506020830135613d2681613cd3565b809150509250929050565b600081518084526020808501945080840160005b83811015613d7757815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613d45565b509495945050505050565b6020815260006136926020830184613d31565b600060208284031215613da757600080fd5b5035919050565b600060208284031215613dc057600080fd5b813567ffffffffffffffff811115613dd757600080fd5b8201610160818503121561369257600080fd5b805182526020810151613e15602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613e3560408401826bffffffffffffffffffffffff169052565b506060810151613e5d606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613e79608084018267ffffffffffffffff169052565b5060a0810151613e9160a084018263ffffffff169052565b5060c0810151613eae60c084018268ffffffffffffffffff169052565b5060e0810151613ecb60e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b61016081016137818284613dea565b60008083601f840112613f2457600080fd5b50813567ffffffffffffffff811115613f3c57600080fd5b6020830191508360208260051b85010111156138f457600080fd5b60008060008060008060008060e0898b031215613f7357600080fd5b606089018a811115613f8457600080fd5b8998503567ffffffffffffffff80821115613f9e57600080fd5b613faa8c838d016138b2565b909950975060808b0135915080821115613fc357600080fd5b613fcf8c838d01613f12565b909750955060a08b0135915080821115613fe857600080fd5b50613ff58b828c01613f12565b999c989b50969995989497949560c00135949350505050565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151614062608084018268ffffffffffffffffff169052565b5060a083015161407b60a084018264ffffffffff169052565b5060c083015161409160c084018261ffff169052565b5060e08301516140c160e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b506101008381015163ffffffff8116848301525b505092915050565b67ffffffffffffffff8116811461267957600080fd5b8035611170816140dd565b60008060008060006080868803121561411657600080fd5b8535614121816140dd565b9450602086013567ffffffffffffffff81111561413d57600080fd5b614149888289016138b2565b909550935050604086013561415d81613a09565b949793965091946060013592915050565b600067ffffffffffffffff8211156141885761418861393d565b5060051b60200190565b600082601f8301126141a357600080fd5b813560206141b86141b38361416e565b6139ba565b82815260059290921b840181019181810190868411156141d757600080fd5b8286015b848110156141fb5780356141ee81613ca6565b83529183019183016141db565b509695505050505050565b803560ff8116811461117057600080fd5b60008060008060008060c0878903121561423057600080fd5b863567ffffffffffffffff8082111561424857600080fd5b6142548a838b01614192565b9750602089013591508082111561426a57600080fd5b6142768a838b01614192565b965061428460408a01614206565b9550606089013591508082111561429a57600080fd5b6142a68a838b01613bdb565b94506142b460808a016140f3565b935060a08901359150808211156142ca57600080fd5b506142d789828a01613bdb565b9150509295509295509295565b6000602082840312156142f657600080fd5b813561369281613ca6565b600181811c9082168061431557607f821691505b60208210810361434e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105ec57600081815260208120601f850160051c8101602086101561437b5750805b601f850160051c820191505b81811015610a8857828155600101614387565b67ffffffffffffffff8311156143b2576143b261393d565b6143c6836143c08354614301565b83614354565b6000601f84116001811461441857600085156143e25750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b1783556144ae565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156144675786850135825560209485019460019092019101614447565b50868210156144a2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b805161117081613a26565b6000602082840312156144d257600080fd5b815161369281613a26565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff828116828216039080821115612661576126616144dd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614591576145916144dd565b5060010190565b600061016082360312156145ab57600080fd5b6145b3613996565b823567ffffffffffffffff8111156145ca57600080fd5b6145d636828601613bdb565b825250602083013560208201526145ef60408401613cc8565b604082015261460060608401613ced565b606082015261461160808401613a3d565b608082015261462260a084016140f3565b60a082015261463360c084016140f3565b60c082015261464460e08401613a1b565b60e0820152610100614657818501613a66565b908201526101206146698482016140f3565b9082015261014061467b848201613cc8565b9082015292915050565b60006020828403121561469757600080fd5b8135613692816140dd565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126146d757600080fd5b83018035915067ffffffffffffffff8211156146f257600080fd5b6020019150368190038213156138f457600080fd5b60006020828403121561471957600080fd5b61369282613a66565b60006020828403121561473457600080fd5b813561369281613a09565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061313660e0830184613dea565b60ff8181168382160190811115613781576137816144dd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061484257614842614800565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b8082028115828204841417613781576137816144dd565b81810381811115613781576137816144dd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff818116838216019080821115612661576126616144dd565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261494a8184018a613d31565b9050828103608084015261495e8189613d31565b905060ff871660a084015282810360c084015261497b8187613b7e565b905067ffffffffffffffff851660e08401528281036101008401526149a08185613b7e565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461117057600080fd5b600080600080600060a086880312156149e257600080fd5b6149eb866149b0565b9450602086015193506040860151925060608601519150614a0e608087016149b0565b90509295509295909350565b60006bffffffffffffffffffffffff80841680614a3957614a39614800565b92169190910492915050565b6bffffffffffffffffffffffff818116838216019080821115612661576126616144dd565b6bffffffffffffffffffffffff8181168382160280821691908281146140d5576140d56144dd565b80820180821115613781576137816144dd565b67ffffffffffffffff818116838216019080821115612661576126616144dd565b600082601f830112614ad757600080fd5b81356020614ae76141b38361416e565b82815260059290921b84018101918181019086841115614b0657600080fd5b8286015b848110156141fb5780358352918301918301614b0a565b600082601f830112614b3257600080fd5b81356020614b426141b38361416e565b82815260059290921b84018101918181019086841115614b6157600080fd5b8286015b848110156141fb57803567ffffffffffffffff811115614b855760008081fd5b614b938986838b0101613bdb565b845250918301918301614b65565b600080600080600060a08688031215614bb957600080fd5b853567ffffffffffffffff80821115614bd157600080fd5b614bdd89838a01614ac6565b96506020880135915080821115614bf357600080fd5b614bff89838a01614b21565b95506040880135915080821115614c1557600080fd5b614c2189838a01614b21565b94506060880135915080821115614c3757600080fd5b614c4389838a01614b21565b93506080880135915080821115614c5957600080fd5b50614c6688828901614b21565b9150509295509295909350565b600082614c8257614c82614800565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614cce8285018b613d31565b91508382036080850152614ce2828a613d31565b915060ff881660a085015283820360c0850152614cff8288613b7e565b90861660e085015283810361010085015290506149a08185613b7e565b805161117081613ca6565b805161117081613cd3565b8051611170816140dd565b805161117081613a09565b805161117081613a48565b60006101608284031215614d6657600080fd5b614d6e613996565b82518152614d7e60208401614d1c565b6020820152614d8f60408401614d27565b6040820152614da060608401614d1c565b6060820152614db160808401614d32565b6080820152614dc260a08401614d3d565b60a0820152614dd360c084016144b5565b60c0820152614de460e084016144b5565b60e0820152610100614df7818501614d48565b90820152610120614e09848201614d48565b90820152610140613b4f848201614d3d565b64ffffffffff818116838216019080821115612661576126616144dd565b6000610200808352614e4d8184018a613b7e565b90508281036020840152614e618189613b7e565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614eaa905060a0830184613dea565b979650505050505050565b60008060408385031215614ec857600080fd5b825160078110614ed757600080fd5b6020840151909250613d2681613cd3565b600060208284031215614efa57600080fd5b5051919050565b60008351614f13818460208801613b5a565b835190830190614f27818360208801613b5a565b0194935050505056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", + Bin: "0x60c06040523480156200001157600080fd5b506040516200560838038062005608833981016040819052620000349162000474565b8282828260013380600081620000915760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c457620000c48162000140565b50505015156080526001600160a01b038116620000f457604051632530e88560e11b815260040160405180910390fd5b6001600160a01b0390811660a052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200013482620001eb565b50505050505062000633565b336001600160a01b038216036200019a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000088565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001f562000349565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160f01b026001600160f01b0364ffffffffff909216600160c81b0264ffffffffff60c81b196001600160481b03909416600160801b0293909316600160801b600160f01b031963ffffffff9586166c010000000000000000000000000263ffffffff60601b19978716680100000000000000000297909716600160401b600160801b0319998716640100000000026001600160401b0319909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e0830151610100840151909216600160e01b026001600160e01b0390921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906200033e9083906200057d565b60405180910390a150565b6200035362000355565b565b6000546001600160a01b03163314620003535760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000088565b80516001600160a01b0381168114620003c957600080fd5b919050565b60405161012081016001600160401b03811182821017156200040057634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff81168114620003c957600080fd5b80516001600160481b0381168114620003c957600080fd5b805164ffffffffff81168114620003c957600080fd5b805161ffff81168114620003c957600080fd5b80516001600160e01b0381168114620003c957600080fd5b60008060008385036101608112156200048c57600080fd5b6200049785620003b1565b935061012080601f1983011215620004ae57600080fd5b620004b8620003ce565b9150620004c86020870162000406565b8252620004d86040870162000406565b6020830152620004eb6060870162000406565b6040830152620004fe6080870162000406565b60608301526200051160a087016200041b565b60808301526200052460c0870162000433565b60a08301526200053760e0870162000449565b60c08301526101006200054c8188016200045c565b60e08401526200055e82880162000406565b90830152509150620005746101408501620003b1565b90509250925092565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151620005d060808401826001600160481b03169052565b5060a0830151620005ea60a084018264ffffffffff169052565b5060c08301516200060160c084018261ffff169052565b5060e08301516200061d60e08401826001600160e01b03169052565b506101009283015163ffffffff16919092015290565b60805160a051614f856200068360003960008181610845015281816109d301528181610ca601528181610f3a015281816110450152818161183001526133b70152600061126e0152614f856000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806381ff7048116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610560578063e4ddcea614610573578063f2fde38b1461058957600080fd5b8063c3f909d4146103b0578063d227d24514610528578063d328a91e1461055857600080fd5b8063a631571e116100bd578063a631571e1461035d578063afcb95d71461037d578063b1dc65a41461039d57600080fd5b806381ff7048146102b557806385b214cf146103225780638da5cb5b1461033557600080fd5b806366316d8d116101455780637f15e1661161011f5780637f15e16614610285578063814118341461029857806381f1b938146102ad57600080fd5b806366316d8d1461026257806379ba5097146102755780637d4807871461027d57600080fd5b8063181f5a7711610176578063181f5a77146101ba5780632a905ccc1461020c57806359b5b7ac1461022e57600080fd5b8063083a5466146101925780631112dadc146101a7575b600080fd5b6101a56101a03660046138fb565b61059c565b005b6101a56101b5366004613aa4565b6105f1565b6101f66040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e312e300000000081525081565b6040516102039190613bc8565b60405180910390f35b610214610841565b60405168ffffffffffffffffff9091168152602001610203565b61021461023c366004613c69565b50600854700100000000000000000000000000000000900468ffffffffffffffffff1690565b6101a5610270366004613cf8565b6108d7565b6101a5610a90565b6101a5610b92565b6101a56102933660046138fb565b610d92565b6102a0610de2565b6040516102039190613d82565b6101f6610e51565b6102ff60015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610203565b6101a5610330366004613d95565b610f22565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610203565b61037061036b366004613dae565b610fd4565b6040516102039190613f03565b604080516001815260006020820181905291810191909152606001610203565b6101a56103ab366004613f57565b611175565b61051b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810468ffffffffffffffffff166080830152790100000000000000000000000000000000000000000000000000810464ffffffffff1660a08301527e01000000000000000000000000000000000000000000000000000000000000900461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08301527c0100000000000000000000000000000000000000000000000000000000900490911661010082015290565b604051610203919061400e565b61053b6105363660046140fe565b61182c565b6040516bffffffffffffffffffffffff9091168152602001610203565b6101f661198c565b6101a561056e366004614217565b6119e3565b61057b61240f565b604051908152602001610203565b6101a56105973660046142e4565b612668565b6105a461267c565b60008190036105df576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105ec82848361439a565b505050565b6105f96126ff565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff64ffffffffff909216790100000000000000000000000000000000000000000000000000027fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90941670010000000000000000000000000000000002939093167fffff0000000000000000000000000000ffffffffffffffffffffffffffffffff63ffffffff9586166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9787166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e08301516101008401519092167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f51848629061083690839061400e565b60405180910390a150565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d291906144c0565b905090565b6108df612707565b806bffffffffffffffffffffffff166000036109195750336000908152600a60205260409020546bffffffffffffffffffffffff16610973565b336000908152600a60205260409020546bffffffffffffffffffffffff80831691161015610973576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906109a09084906bffffffffffffffffffffffff1661450c565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506109f57f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b158015610a7457600080fd5b505af1158015610a88573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b9a6126ff565b610ba2612707565b6000610bac610de2565b905060005b8151811015610d8e576000600a6000848481518110610bd257610bd2614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d7d576000600a6000858581518110610c3157610c31614531565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610cc87f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610cf557610cf5614531565b6020026020010151836040518363ffffffff1660e01b8152600401610d4a92919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d6457600080fd5b505af1158015610d78573d6000803e3d6000fd5b505050505b50610d8781614560565b9050610bb1565b5050565b610d9a61267c565b6000819003610dd5576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105ec82848361439a565b60606006805480602002602001604051908101604052809291908181526020018280548015610e4757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e1c575b5050505050905090565b6060600d8054610e6090614301565b9050600003610e9b576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610ea890614301565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed490614301565b8015610e475780601f10610ef657610100808354040283529160200191610e47565b820191906000526020600020905b815481529060010190602001808311610f0457509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f91576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f416906108369083815260200190565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461109c576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110ad6110a883614598565b6128b3565b90506110bf60608301604084016142e4565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff3261110d60c0870160a08801614685565b61111f610160880161014089016142e4565b61112988806146a2565b61113b6101208b016101008c01614707565b60208b01356111516101008d0160e08e01614722565b8b6040516111679998979695949392919061473f565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16040805160608101825260025480825260035460ff8082166020850152610100909104169282019290925290831461125c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f6e666967446967657374206d69736d6174636800000000000000000000006044820152606401610b0d565b61126a8b8b8b8b8b8b612d51565b60007f0000000000000000000000000000000000000000000000000000000000000000156112c7576002826020015183604001516112a891906147e7565b6112b2919061482f565b6112bd9060016147e7565b60ff1690506112dd565b60208201516112d79060016147e7565b60ff1690505b888114611346576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610b0d565b8887146113af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f7369676e617475726573206f7574206f6620726567697374726174696f6e00006044820152606401610b0d565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113f2576113f2614851565b600281111561140357611403614851565b905250905060028160200151600281111561142057611420614851565b14801561146757506006816000015160ff168154811061144257611442614531565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b6114cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610b0d565b50505050506114da613893565b6000808a8a6040516114ed929190614880565b604051908190038120611504918e90602001614890565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b8981101561180e57600060018489846020811061156d5761156d614531565b61157a91901a601b6147e7565b8e8e8681811061158c5761158c614531565b905060200201358d8d878181106115a5576115a5614531565b90506020020135604051600081526020016040526040516115e2949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611604573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff8082168552929650929450840191610100900416600281111561168457611684614851565b600281111561169557611695614851565b90525092506001836020015160028111156116b2576116b2614851565b14611719576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610b0d565b8251600090879060ff16601f811061173357611733614531565b602002015173ffffffffffffffffffffffffffffffffffffffff16146117b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610b0d565b8086846000015160ff16601f81106117cf576117cf614531565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117fa6001866147e7565b9450508061180790614560565b905061154e565b50505061181f833383858e8e612e08565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b1580156118cc57600080fd5b505afa1580156118e0573d6000803e3d6000fd5b5050505066038d7ea4c68000821115611925576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061192f610841565b9050600061197287878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061023c92505050565b905061198085858385612fd7565b98975050505050505050565b6060600c805461199b90614301565b90506000036119d6576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610ea890614301565b855185518560ff16601f831115611a56576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610b0d565b80600003611ac0576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610b0d565b818314611b4e576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610b0d565b611b598160036148a4565b8311611bc1576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610b0d565b611bc961267c565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611c109088613144565b60055415611dc557600554600090611c2a906001906148bb565b9050600060058281548110611c4157611c41614531565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611c7b57611c7b614531565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611cfb57611cfb6148ce565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611d6457611d646148ce565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611c10915050565b60005b81515181101561222c5760006004600084600001518481518110611dee57611dee614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611e3857611e38614851565b14611e9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610b0d565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611ed057611ed0614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115611f7157611f71614851565b021790555060009150611f819050565b6004600084602001518481518110611f9b57611f9b614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611fe557611fe5614851565b1461204c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610b0d565b6040805180820190915260ff82168152602081016002815250600460008460200151848151811061207f5761207f614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561212057612120614851565b02179055505082518051600592508390811061213e5761213e614531565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90931692909217909155820151805160069190839081106121ba576121ba614531565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790558061222481614560565b915050611dc8565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff43811682029290921780855592048116929182916014916122e4918491740100000000000000000000000000000000000000009004166148fd565b92506101000a81548163ffffffff021916908363ffffffff1602179055506123434630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a0015161315d565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986123fa988b9891977401000000000000000000000000000000000000000090920463ffffffff1696909591949193919261491a565b60405180910390a15050505050505050505050565b604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c0100000000000000000000000080830482166060850152700100000000000000000000000000000000830468ffffffffffffffffff166080850152790100000000000000000000000000000000000000000000000000830464ffffffffff1660a0808601919091527e0100000000000000000000000000000000000000000000000000000000000090930461ffff1660c08501526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08601527c01000000000000000000000000000000000000000000000000000000009004909116610100840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa15801561259d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c191906149ca565b5093505092505080426125d491906148bb565b836020015163ffffffff161080156125f657506000836020015163ffffffff16115b1561262457505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b60008213612661576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610b0d565b5092915050565b61267061267c565b61267981613208565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146126fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0d565b565b6126fd61267c565b600b546bffffffffffffffffffffffff1660000361272157565b600061272b610de2565b8051909150600081900361276b576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b5460009061278a9083906bffffffffffffffffffffffff16614a1a565b905060005b828110156128555781600a60008684815181106127ae576127ae614531565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff166128169190614a45565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508061284e90614560565b905061278f565b506128608282614a6a565b600b80546000906128809084906bffffffffffffffffffffffff1661450c565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c0100000000000000000000000081048316606083015268ffffffffffffffffff700100000000000000000000000000000000820416608083015264ffffffffff79010000000000000000000000000000000000000000000000000082041660a083015261ffff7e01000000000000000000000000000000000000000000000000000000000000909104811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08501527c0100000000000000000000000000000000000000000000000000000000900490931661010080840191909152850151919291161115612a6e576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854600090700100000000000000000000000000000000900468ffffffffffffffffff1690506000612aab8560e001513a848860800151612fd7565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612b07576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083610100015163ffffffff1642612b209190614a92565b905060003087604001518860a001518960c001516001612b409190614aa5565b8a5180516020918201206101008d015160e08e0151604051612bf498979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b6040516020818303038152906040528051906020012090506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001846bffffffffffffffffffffffff168152602001886040015173ffffffffffffffffffffffffffffffffffffffff1681526020018860a0015167ffffffffffffffff1681526020018860e0015163ffffffff168152602001886080015168ffffffffffffffffff1681526020018568ffffffffffffffffff168152602001866040015163ffffffff1664ffffffffff168152602001866060015163ffffffff1664ffffffffff1681526020018363ffffffff16815250955085604051602001612d039190613f03565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009384526007909252909120555092949350505050565b6000612d5e8260206148a4565b612d698560206148a4565b612d7588610144614a92565b612d7f9190614a92565b612d899190614a92565b612d94906000614a92565b9050368114612dff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610b0d565b50505050505050565b606080808080612e1a86880188614ba1565b84519499509297509095509350915060ff16801580612e3a575084518114155b80612e46575083518114155b80612e52575082518114155b80612e5e575081518114155b15612e95576040517f0be3632800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015612fc8576000612f2d888381518110612eb757612eb7614531565b6020026020010151888481518110612ed157612ed1614531565b6020026020010151888581518110612eeb57612eeb614531565b6020026020010151888681518110612f0557612f05614531565b6020026020010151888781518110612f1f57612f1f614531565b6020026020010151886132fd565b90506000816006811115612f4357612f43614851565b1480612f6057506001816006811115612f5e57612f5e614851565b145b15612fb757878281518110612f7757612f77614531565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b50612fc181614560565b9050612e98565b50505050505050505050505050565b600854600090790100000000000000000000000000000000000000000000000000900464ffffffffff1684101561303257600854790100000000000000000000000000000000000000000000000000900464ffffffffff1693505b6008546000906127109061304c9063ffffffff16876148a4565b6130569190614c73565b6130609086614a92565b60085490915060009087906130999063ffffffff6c010000000000000000000000008204811691680100000000000000009004166148fd565b6130a391906148fd565b63ffffffff16905060006130ed6000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061361192505050565b9050600061310e826130ff85876148a4565b6131099190614a92565b613753565b9050600061312a68ffffffffffffffffff808916908a16614a45565b90506131368183614a45565b9a9950505050505050505050565b600061314e610de2565b511115610d8e57610d8e612707565b6000808a8a8a8a8a8a8a8a8a60405160200161318199989796959493929190614c87565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613287576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080848060200190518101906133149190614d53565b905060003a82610120015183610100015161332f9190614e1b565b64ffffffffff1661334091906148a4565b905060008460ff166133886000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061361192505050565b6133929190614c73565b905060006133a36131098385614a92565b905060006133b03a613753565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298e8e868b60e0015168ffffffffffffffffff168961340f9190614a45565b338d6040518763ffffffff1660e01b815260040161343296959493929190614e39565b60408051808303816000875af1158015613450573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134749190614eb5565b9092509050600082600681111561348d5761348d614851565b14806134aa575060018260068111156134a8576134a8614851565b145b156136005760008e8152600760205260408120556134c88185614a45565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0890151600b805468ffffffffffffffffff9092169390929161353491859116614a45565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508d7f90815c2e624694e8010bffad2bcefaf96af282ef1bc2ebc0042d1b89a585e0468487848b60c0015168ffffffffffffffffff168c60e0015168ffffffffffffffffff16878b6135b39190614a45565b6135bd9190614a45565b6135c79190614a45565b604080516bffffffffffffffffffffffff9586168152602081019490945291841683830152909216606082015290519081900360800190a25b509c9b505050505050505050505050565b60004661361d81613787565b1561369957606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561366e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136929190614ee8565b9392505050565b6136a2816137aa565b1561374a5773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e84604051806080016040528060488152602001614f3160489139604051602001613702929190614f01565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161372d9190613bc8565b602060405180830381865afa15801561366e573d6000803e3d6000fd5b50600092915050565b600061378161376061240f565b61377284670de0b6b3a76400006148a4565b61377c9190614c73565b6137f1565b92915050565b600061a4b182148061379b575062066eed82145b8061378157505062066eee1490565b6000600a8214806137bc57506101a482145b806137c9575062aa37dc82145b806137d5575061210582145b806137e2575062014a3382145b8061378157505062014a341490565b60006bffffffffffffffffffffffff82111561388f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b0d565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f8401126138c457600080fd5b50813567ffffffffffffffff8111156138dc57600080fd5b6020830191508360208285010111156138f457600080fd5b9250929050565b6000806020838503121561390e57600080fd5b823567ffffffffffffffff81111561392557600080fd5b613931858286016138b2565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156139905761399061393d565b60405290565b604051610160810167ffffffffffffffff811182821017156139905761399061393d565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613a0157613a0161393d565b604052919050565b63ffffffff8116811461267957600080fd5b803561117081613a09565b68ffffffffffffffffff8116811461267957600080fd5b803561117081613a26565b64ffffffffff8116811461267957600080fd5b803561117081613a48565b803561ffff8116811461117057600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461117057600080fd5b60006101208284031215613ab757600080fd5b613abf61396c565b613ac883613a1b565b8152613ad660208401613a1b565b6020820152613ae760408401613a1b565b6040820152613af860608401613a1b565b6060820152613b0960808401613a3d565b6080820152613b1a60a08401613a5b565b60a0820152613b2b60c08401613a66565b60c0820152613b3c60e08401613a78565b60e0820152610100613b4f818501613a1b565b908201529392505050565b60005b83811015613b75578181015183820152602001613b5d565b50506000910152565b60008151808452613b96816020860160208601613b5a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006136926020830184613b7e565b600082601f830112613bec57600080fd5b813567ffffffffffffffff811115613c0657613c0661393d565b613c3760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016139ba565b818152846020838601011115613c4c57600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215613c7b57600080fd5b813567ffffffffffffffff811115613c9257600080fd5b613c9e84828501613bdb565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461267957600080fd5b803561117081613ca6565b6bffffffffffffffffffffffff8116811461267957600080fd5b803561117081613cd3565b60008060408385031215613d0b57600080fd5b8235613d1681613ca6565b91506020830135613d2681613cd3565b809150509250929050565b600081518084526020808501945080840160005b83811015613d7757815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613d45565b509495945050505050565b6020815260006136926020830184613d31565b600060208284031215613da757600080fd5b5035919050565b600060208284031215613dc057600080fd5b813567ffffffffffffffff811115613dd757600080fd5b8201610160818503121561369257600080fd5b805182526020810151613e15602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613e3560408401826bffffffffffffffffffffffff169052565b506060810151613e5d606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613e79608084018267ffffffffffffffff169052565b5060a0810151613e9160a084018263ffffffff169052565b5060c0810151613eae60c084018268ffffffffffffffffff169052565b5060e0810151613ecb60e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b61016081016137818284613dea565b60008083601f840112613f2457600080fd5b50813567ffffffffffffffff811115613f3c57600080fd5b6020830191508360208260051b85010111156138f457600080fd5b60008060008060008060008060e0898b031215613f7357600080fd5b606089018a811115613f8457600080fd5b8998503567ffffffffffffffff80821115613f9e57600080fd5b613faa8c838d016138b2565b909950975060808b0135915080821115613fc357600080fd5b613fcf8c838d01613f12565b909750955060a08b0135915080821115613fe857600080fd5b50613ff58b828c01613f12565b999c989b50969995989497949560c00135949350505050565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151614062608084018268ffffffffffffffffff169052565b5060a083015161407b60a084018264ffffffffff169052565b5060c083015161409160c084018261ffff169052565b5060e08301516140c160e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b506101008381015163ffffffff8116848301525b505092915050565b67ffffffffffffffff8116811461267957600080fd5b8035611170816140dd565b60008060008060006080868803121561411657600080fd5b8535614121816140dd565b9450602086013567ffffffffffffffff81111561413d57600080fd5b614149888289016138b2565b909550935050604086013561415d81613a09565b949793965091946060013592915050565b600067ffffffffffffffff8211156141885761418861393d565b5060051b60200190565b600082601f8301126141a357600080fd5b813560206141b86141b38361416e565b6139ba565b82815260059290921b840181019181810190868411156141d757600080fd5b8286015b848110156141fb5780356141ee81613ca6565b83529183019183016141db565b509695505050505050565b803560ff8116811461117057600080fd5b60008060008060008060c0878903121561423057600080fd5b863567ffffffffffffffff8082111561424857600080fd5b6142548a838b01614192565b9750602089013591508082111561426a57600080fd5b6142768a838b01614192565b965061428460408a01614206565b9550606089013591508082111561429a57600080fd5b6142a68a838b01613bdb565b94506142b460808a016140f3565b935060a08901359150808211156142ca57600080fd5b506142d789828a01613bdb565b9150509295509295509295565b6000602082840312156142f657600080fd5b813561369281613ca6565b600181811c9082168061431557607f821691505b60208210810361434e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105ec57600081815260208120601f850160051c8101602086101561437b5750805b601f850160051c820191505b81811015610a8857828155600101614387565b67ffffffffffffffff8311156143b2576143b261393d565b6143c6836143c08354614301565b83614354565b6000601f84116001811461441857600085156143e25750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b1783556144ae565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156144675786850135825560209485019460019092019101614447565b50868210156144a2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b805161117081613a26565b6000602082840312156144d257600080fd5b815161369281613a26565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff828116828216039080821115612661576126616144dd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614591576145916144dd565b5060010190565b600061016082360312156145ab57600080fd5b6145b3613996565b823567ffffffffffffffff8111156145ca57600080fd5b6145d636828601613bdb565b825250602083013560208201526145ef60408401613cc8565b604082015261460060608401613ced565b606082015261461160808401613a3d565b608082015261462260a084016140f3565b60a082015261463360c084016140f3565b60c082015261464460e08401613a1b565b60e0820152610100614657818501613a66565b908201526101206146698482016140f3565b9082015261014061467b848201613cc8565b9082015292915050565b60006020828403121561469757600080fd5b8135613692816140dd565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126146d757600080fd5b83018035915067ffffffffffffffff8211156146f257600080fd5b6020019150368190038213156138f457600080fd5b60006020828403121561471957600080fd5b61369282613a66565b60006020828403121561473457600080fd5b813561369281613a09565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061313660e0830184613dea565b60ff8181168382160190811115613781576137816144dd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061484257614842614800565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b8082028115828204841417613781576137816144dd565b81810381811115613781576137816144dd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff818116838216019080821115612661576126616144dd565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261494a8184018a613d31565b9050828103608084015261495e8189613d31565b905060ff871660a084015282810360c084015261497b8187613b7e565b905067ffffffffffffffff851660e08401528281036101008401526149a08185613b7e565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461117057600080fd5b600080600080600060a086880312156149e257600080fd5b6149eb866149b0565b9450602086015193506040860151925060608601519150614a0e608087016149b0565b90509295509295909350565b60006bffffffffffffffffffffffff80841680614a3957614a39614800565b92169190910492915050565b6bffffffffffffffffffffffff818116838216019080821115612661576126616144dd565b6bffffffffffffffffffffffff8181168382160280821691908281146140d5576140d56144dd565b80820180821115613781576137816144dd565b67ffffffffffffffff818116838216019080821115612661576126616144dd565b600082601f830112614ad757600080fd5b81356020614ae76141b38361416e565b82815260059290921b84018101918181019086841115614b0657600080fd5b8286015b848110156141fb5780358352918301918301614b0a565b600082601f830112614b3257600080fd5b81356020614b426141b38361416e565b82815260059290921b84018101918181019086841115614b6157600080fd5b8286015b848110156141fb57803567ffffffffffffffff811115614b855760008081fd5b614b938986838b0101613bdb565b845250918301918301614b65565b600080600080600060a08688031215614bb957600080fd5b853567ffffffffffffffff80821115614bd157600080fd5b614bdd89838a01614ac6565b96506020880135915080821115614bf357600080fd5b614bff89838a01614b21565b95506040880135915080821115614c1557600080fd5b614c2189838a01614b21565b94506060880135915080821115614c3757600080fd5b614c4389838a01614b21565b93506080880135915080821115614c5957600080fd5b50614c6688828901614b21565b9150509295509295909350565b600082614c8257614c82614800565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614cce8285018b613d31565b91508382036080850152614ce2828a613d31565b915060ff881660a085015283820360c0850152614cff8288613b7e565b90861660e085015283810361010085015290506149a08185613b7e565b805161117081613ca6565b805161117081613cd3565b8051611170816140dd565b805161117081613a09565b805161117081613a48565b60006101608284031215614d6657600080fd5b614d6e613996565b82518152614d7e60208401614d1c565b6020820152614d8f60408401614d27565b6040820152614da060608401614d1c565b6060820152614db160808401614d32565b6080820152614dc260a08401614d3d565b60a0820152614dd360c084016144b5565b60c0820152614de460e084016144b5565b60e0820152610100614df7818501614d48565b90820152610120614e09848201614d48565b90820152610140613b4f848201614d3d565b64ffffffffff818116838216019080821115612661576126616144dd565b6000610200808352614e4d8184018a613b7e565b90508281036020840152614e618189613b7e565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614eaa905060a0830184613dea565b979650505050505050565b60008060408385031215614ec857600080fd5b825160078110614ed757600080fd5b6020840151909250613d2681613cd3565b600060208284031215614efa57600080fd5b5051919050565b60008351614f13818460208801613b5a565b835190830190614f27818360208801613b5a565b0194935050505056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", } var FunctionsCoordinatorABI = FunctionsCoordinatorMetaData.ABI diff --git a/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 41524c3a829..534e5543e86 100644 --- a/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -4,7 +4,7 @@ functions_allow_list: ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServ functions_billing_registry_events_mock: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistryEventsMock.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistryEventsMock.bin 50deeb883bd9c3729702be335c0388f9d8553bab4be5e26ecacac496a89e2b77 functions_client: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClient.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClient.bin 2368f537a04489c720a46733f8596c4fc88a31062ecfa966d05f25dd98608aca functions_client_example: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClientExample.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClientExample.bin abf32e69f268f40e8530eb8d8e96bf310b798a4c0049a58022d9d2fb527b601b -functions_coordinator: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.bin 96416d5be2ae4625395567397da88f71b215005cf8ad71a1cdaa56e6b5e16908 +functions_coordinator: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.bin 38e168fa57c9626140e1e4d05f4124b4b69bd775e6e0f4481e017ad86c4d95a0 functions_load_test_client: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsLoadTestClient.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsLoadTestClient.bin c8dbbd5ebb34435800d6674700068837c3a252db60046a14b0e61e829db517de functions_oracle_events_mock: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracleEventsMock.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracleEventsMock.bin 3ca70f966f8fe751987f0ccb50bebb6aa5be77e4a9f835d1ae99e0e9bfb7d52c functions_router: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.bin 9dedd3a36043605fd9bedf821e7ec5b4281a5c7ae2e4a1955f37aff8ba13519f From 96ae30c1eecd5251f1830ba6c40b83863fe0fa65 Mon Sep 17 00:00:00 2001 From: Justin Kaseman Date: Thu, 9 Nov 2023 21:24:25 -0500 Subject: [PATCH 7/7] Remove Functions OCR2Base config digest check & use custom errors (#11249) --- .../gas-snapshots/functions.gas-snapshot | 44 +++++++-------- .../dev/v1_X/FunctionsCoordinator.sol | 6 ++- .../v0.8/functions/dev/v1_X/ocr/OCR2Base.sol | 54 ++++++------------- .../functions_coordinator.go | 4 +- ...rapper-dependency-versions-do-not-edit.txt | 2 +- 5 files changed, 46 insertions(+), 64 deletions(-) diff --git a/contracts/gas-snapshots/functions.gas-snapshot b/contracts/gas-snapshots/functions.gas-snapshot index d15666f8857..521b3bffac1 100644 --- a/contracts/gas-snapshots/functions.gas-snapshot +++ b/contracts/gas-snapshots/functions.gas-snapshot @@ -1,12 +1,12 @@ -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 14534206) -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14534184) -ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14534200) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14545620) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14545597) -ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14545569) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14545520) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14545509) -ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14545553) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 14600662) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14600640) +ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14600656) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14612076) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14612053) +ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14612025) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14611976) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14611965) +ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14612009) FunctionsBilling_Constructor:test_Constructor_Success() (gas: 14812) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_RevertIfNotRouter() (gas: 13282) FunctionsBilling_DeleteCommitment:test_DeleteCommitment_Success() (gas: 15897) @@ -29,8 +29,8 @@ FunctionsBilling__DisperseFeePool:test__DisperseFeePool_RevertIfNotSet() (gas: 8 FunctionsBilling__FulfillAndBill:test__FulfillAndBill_RevertIfInvalidCommitment() (gas: 13302) FunctionsBilling__FulfillAndBill:test__FulfillAndBill_Success() (gas: 180763) FunctionsClient_Constructor:test_Constructor_Success() (gas: 7573) -FunctionsClient_FulfillRequest:test_FulfillRequest_MaximumGas() (gas: 504354) -FunctionsClient_FulfillRequest:test_FulfillRequest_MinimumGas() (gas: 205558) +FunctionsClient_FulfillRequest:test_FulfillRequest_MaximumGas() (gas: 497786) +FunctionsClient_FulfillRequest:test_FulfillRequest_MinimumGas() (gas: 198990) FunctionsClient_HandleOracleFulfillment:test_HandleOracleFulfillment_RevertIfNotRouter() (gas: 14623) FunctionsClient_HandleOracleFulfillment:test_HandleOracleFulfillment_Success() (gas: 22923) FunctionsClient__SendRequest:test__SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 55059) @@ -51,17 +51,17 @@ FunctionsRequest_DEFAULT_BUFFER_SIZE:test_DEFAULT_BUFFER_SIZE() (gas: 246) FunctionsRequest_EncodeCBOR:test_EncodeCBOR_Success() (gas: 223) FunctionsRequest_REQUEST_DATA_VERSION:test_REQUEST_DATA_VERSION() (gas: 225) FunctionsRouter_Constructor:test_Constructor_Success() (gas: 12007) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 174027) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 164358) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 167459) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 157790) FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidCommitment() (gas: 38115) FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidRequestId() (gas: 35238) -FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 182503) +FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 175935) FunctionsRouter_Fulfill:test_Fulfill_RevertIfNotCommittedCoordinator() (gas: 28086) -FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 158046) -FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 327605) -FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 341226) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2516507) -FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 546986) +FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 151478) +FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 321037) +FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 334658) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2509939) +FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 540418) FunctionsRouter_GetAdminFee:test_GetAdminFee_Success() (gas: 17983) FunctionsRouter_GetAllowListId:test_GetAllowListId_Success() (gas: 12904) FunctionsRouter_GetConfig:test_GetConfig_Success() (gas: 37159) @@ -141,11 +141,11 @@ FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_Reve FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_RevertIfStartIsAfterEnd() (gas: 13459) FunctionsSubscriptions_GetSubscriptionsInRange:test_GetSubscriptionsInRange_Success() (gas: 59592) FunctionsSubscriptions_GetTotalBalance:test_GetTotalBalance_Success() (gas: 15010) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata(uint96) (runs: 256, μ: 43685, ~: 45548) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96) (runs: 256, μ: 46197, ~: 48060) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata(uint96) (runs: 256, μ: 43863, ~: 45548) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96) (runs: 256, μ: 46375, ~: 48060) FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink(uint96) (runs: 256, μ: 14295, ~: 14295) FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused(uint96) (runs: 256, μ: 51177, ~: 53040) -FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 85879, ~: 89604) +FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 86057, ~: 89604) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfAmountMoreThanBalance() (gas: 20745) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfBalanceInvariant() (gas: 189) FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfNoAmount() (gas: 15638) diff --git a/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol b/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol index 3ee4931e97c..15949a497e7 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/FunctionsCoordinator.sol @@ -44,7 +44,7 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli address router, Config memory config, address linkToNativeFeed - ) OCR2Base(true) FunctionsBilling(router, config, linkToNativeFeed) {} + ) OCR2Base() FunctionsBilling(router, config, linkToNativeFeed) {} /// @inheritdoc IFunctionsCoordinator function getThresholdPublicKey() external view override returns (bytes memory) { @@ -151,7 +151,9 @@ contract FunctionsCoordinator is OCR2Base, IFunctionsCoordinator, FunctionsBilli numberOfFulfillments != onchainMetadata.length || numberOfFulfillments != offchainMetadata.length ) { - revert ReportInvalid(); + revert ReportInvalid( + "All fields on the report must be of equal length: requestIds, results, errors, onchainMetadata, offchainMetadata" + ); } // Bounded by "MaxRequestBatchSize" on the Job's ReportingPluginConfig diff --git a/contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Base.sol b/contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Base.sol index dd9ea84a519..375159bf4c9 100644 --- a/contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Base.sol +++ b/contracts/src/v0.8/functions/dev/v1_X/ocr/OCR2Base.sol @@ -10,17 +10,10 @@ import {OCR2Abstract} from "./OCR2Abstract.sol"; * doc, which refers to this contract as simply the "contract". */ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { - error ReportInvalid(); + error ReportInvalid(string message); error InvalidConfig(string message); - bool internal immutable i_uniqueReports; - - constructor(bool uniqueReports) ConfirmedOwner(msg.sender) { - i_uniqueReports = uniqueReports; - } - - // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables - uint256 private constant maxUint32 = (1 << 32) - 1; + constructor() ConfirmedOwner(msg.sender) {} // incremented each time a new config is posted. This count is incorporated // into the config digest, to prevent replay attacks. @@ -144,12 +137,12 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { // Bounded by MAX_NUM_ORACLES in OCR2Abstract.sol for (uint256 i = 0; i < args.signers.length; i++) { + if (args.signers[i] == address(0)) revert InvalidConfig("signer must not be empty"); + if (args.transmitters[i] == address(0)) revert InvalidConfig("transmitter must not be empty"); // add new signer/transmitter addresses - // solhint-disable-next-line custom-errors - require(s_oracles[args.signers[i]].role == Role.Unset, "repeated signer address"); + if (s_oracles[args.signers[i]].role != Role.Unset) revert InvalidConfig("repeated signer address"); s_oracles[args.signers[i]] = Oracle(uint8(i), Role.Signer); - // solhint-disable-next-line custom-errors - require(s_oracles[args.transmitters[i]].role == Role.Unset, "repeated transmitter address"); + if (s_oracles[args.transmitters[i]].role != Role.Unset) revert InvalidConfig("repeated transmitter address"); s_oracles[args.transmitters[i]] = Oracle(uint8(i), Role.Transmitter); s_signers.push(args.signers[i]); s_transmitters.push(args.transmitters[i]); @@ -287,8 +280,7 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { ss.length * 32 + // 32 bytes per entry in _ss 0; // placeholder - // solhint-disable-next-line custom-errors - require(msg.data.length == expected, "calldata length mismatch"); + if (msg.data.length != expected) revert ReportInvalid("calldata length mismatch"); } /** @@ -319,30 +311,20 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { emit Transmitted(configDigest, uint32(epochAndRound >> 8)); - ConfigInfo memory configInfo = s_configInfo; - // solhint-disable-next-line custom-errors - require(configInfo.latestConfigDigest == configDigest, "configDigest mismatch"); + // The following check is disabled to allow both current and proposed routes to submit reports using the same OCR config digest + // Chainlink Functions uses globally unique request IDs. Metadata about the request is stored and checked in the Coordinator and Router + // require(configInfo.latestConfigDigest == configDigest, "configDigest mismatch"); _requireExpectedMsgDataLength(report, rs, ss); - uint256 expectedNumSignatures; - if (i_uniqueReports) { - expectedNumSignatures = (configInfo.n + configInfo.f) / 2 + 1; - } else { - expectedNumSignatures = configInfo.f + 1; - } + uint256 expectedNumSignatures = (s_configInfo.n + s_configInfo.f) / 2 + 1; - // solhint-disable-next-line custom-errors - require(rs.length == expectedNumSignatures, "wrong number of signatures"); - // solhint-disable-next-line custom-errors - require(rs.length == ss.length, "signatures out of registration"); + if (rs.length != expectedNumSignatures) revert ReportInvalid("wrong number of signatures"); + if (rs.length != ss.length) revert ReportInvalid("report rs and ss must be of equal length"); Oracle memory transmitter = s_oracles[msg.sender]; - // solhint-disable-next-line custom-errors - require( // Check that sender is authorized to report - transmitter.role == Role.Transmitter && msg.sender == s_transmitters[transmitter.index], - "unauthorized transmitter" - ); + if (transmitter.role != Role.Transmitter && msg.sender != s_transmitters[transmitter.index]) + revert ReportInvalid("unauthorized transmitter"); } address[MAX_NUM_ORACLES] memory signed; @@ -357,10 +339,8 @@ abstract contract OCR2Base is ConfirmedOwner, OCR2Abstract { for (uint256 i = 0; i < rs.length; ++i) { address signer = ecrecover(h, uint8(rawVs[i]) + 27, rs[i], ss[i]); o = s_oracles[signer]; - // solhint-disable-next-line custom-errors - require(o.role == Role.Signer, "address not authorized to sign"); - // solhint-disable-next-line custom-errors - require(signed[o.index] == address(0), "non-unique signature"); + if (o.role != Role.Signer) revert ReportInvalid("address not authorized to sign"); + if (signed[o.index] != address(0)) revert ReportInvalid("non-unique signature"); signed[o.index] = signer; signerCount += 1; } diff --git a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go index 917107524bf..3e3fac16d13 100644 --- a/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go +++ b/core/gethwrappers/functions/generated/functions_coordinator/functions_coordinator.go @@ -71,8 +71,8 @@ type FunctionsResponseRequestMeta struct { } var FunctionsCoordinatorMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"linkToNativeFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPublicKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InconsistentReportData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoTransmittersSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouterOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ReportInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustBeSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedPublicKeyChange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedRequestDataVersion\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CommitmentDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"callbackGasLimit\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"OracleResponse\",\"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\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"juelsPerGas\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1FeeShareWei\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"callbackCostJuels\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalCostJuels\",\"type\":\"uint96\"}],\"name\":\"RequestBilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"deleteCommitment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"gasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateCost\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getDONFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getThresholdPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracleWithdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"_f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"_offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"donPublicKey\",\"type\":\"bytes\"}],\"name\":\"setDONPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"thresholdPublicKey\",\"type\":\"bytes\"}],\"name\":\"setThresholdPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"availableBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"}],\"internalType\":\"structFunctionsResponse.RequestMeta\",\"name\":\"request\",\"type\":\"tuple\"}],\"name\":\"startRequest\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"transmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x60c06040523480156200001157600080fd5b506040516200560838038062005608833981016040819052620000349162000474565b8282828260013380600081620000915760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c457620000c48162000140565b50505015156080526001600160a01b038116620000f457604051632530e88560e11b815260040160405180910390fd5b6001600160a01b0390811660a052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200013482620001eb565b50505050505062000633565b336001600160a01b038216036200019a5760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000088565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001f562000349565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160f01b026001600160f01b0364ffffffffff909216600160c81b0264ffffffffff60c81b196001600160481b03909416600160801b0293909316600160801b600160f01b031963ffffffff9586166c010000000000000000000000000263ffffffff60601b19978716680100000000000000000297909716600160401b600160801b0319998716640100000000026001600160401b0319909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e0830151610100840151909216600160e01b026001600160e01b0390921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906200033e9083906200057d565b60405180910390a150565b6200035362000355565b565b6000546001600160a01b03163314620003535760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000088565b80516001600160a01b0381168114620003c957600080fd5b919050565b60405161012081016001600160401b03811182821017156200040057634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff81168114620003c957600080fd5b80516001600160481b0381168114620003c957600080fd5b805164ffffffffff81168114620003c957600080fd5b805161ffff81168114620003c957600080fd5b80516001600160e01b0381168114620003c957600080fd5b60008060008385036101608112156200048c57600080fd5b6200049785620003b1565b935061012080601f1983011215620004ae57600080fd5b620004b8620003ce565b9150620004c86020870162000406565b8252620004d86040870162000406565b6020830152620004eb6060870162000406565b6040830152620004fe6080870162000406565b60608301526200051160a087016200041b565b60808301526200052460c0870162000433565b60a08301526200053760e0870162000449565b60c08301526101006200054c8188016200045c565b60e08401526200055e82880162000406565b90830152509150620005746101408501620003b1565b90509250925092565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151620005d060808401826001600160481b03169052565b5060a0830151620005ea60a084018264ffffffffff169052565b5060c08301516200060160c084018261ffff169052565b5060e08301516200061d60e08401826001600160e01b03169052565b506101009283015163ffffffff16919092015290565b60805160a051614f856200068360003960008181610845015281816109d301528181610ca601528181610f3a015281816110450152818161183001526133b70152600061126e0152614f856000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806381ff7048116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610560578063e4ddcea614610573578063f2fde38b1461058957600080fd5b8063c3f909d4146103b0578063d227d24514610528578063d328a91e1461055857600080fd5b8063a631571e116100bd578063a631571e1461035d578063afcb95d71461037d578063b1dc65a41461039d57600080fd5b806381ff7048146102b557806385b214cf146103225780638da5cb5b1461033557600080fd5b806366316d8d116101455780637f15e1661161011f5780637f15e16614610285578063814118341461029857806381f1b938146102ad57600080fd5b806366316d8d1461026257806379ba5097146102755780637d4807871461027d57600080fd5b8063181f5a7711610176578063181f5a77146101ba5780632a905ccc1461020c57806359b5b7ac1461022e57600080fd5b8063083a5466146101925780631112dadc146101a7575b600080fd5b6101a56101a03660046138fb565b61059c565b005b6101a56101b5366004613aa4565b6105f1565b6101f66040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e312e300000000081525081565b6040516102039190613bc8565b60405180910390f35b610214610841565b60405168ffffffffffffffffff9091168152602001610203565b61021461023c366004613c69565b50600854700100000000000000000000000000000000900468ffffffffffffffffff1690565b6101a5610270366004613cf8565b6108d7565b6101a5610a90565b6101a5610b92565b6101a56102933660046138fb565b610d92565b6102a0610de2565b6040516102039190613d82565b6101f6610e51565b6102ff60015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610203565b6101a5610330366004613d95565b610f22565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610203565b61037061036b366004613dae565b610fd4565b6040516102039190613f03565b604080516001815260006020820181905291810191909152606001610203565b6101a56103ab366004613f57565b611175565b61051b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810468ffffffffffffffffff166080830152790100000000000000000000000000000000000000000000000000810464ffffffffff1660a08301527e01000000000000000000000000000000000000000000000000000000000000900461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08301527c0100000000000000000000000000000000000000000000000000000000900490911661010082015290565b604051610203919061400e565b61053b6105363660046140fe565b61182c565b6040516bffffffffffffffffffffffff9091168152602001610203565b6101f661198c565b6101a561056e366004614217565b6119e3565b61057b61240f565b604051908152602001610203565b6101a56105973660046142e4565b612668565b6105a461267c565b60008190036105df576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105ec82848361439a565b505050565b6105f96126ff565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff64ffffffffff909216790100000000000000000000000000000000000000000000000000027fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90941670010000000000000000000000000000000002939093167fffff0000000000000000000000000000ffffffffffffffffffffffffffffffff63ffffffff9586166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9787166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e08301516101008401519092167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f51848629061083690839061400e565b60405180910390a150565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d291906144c0565b905090565b6108df612707565b806bffffffffffffffffffffffff166000036109195750336000908152600a60205260409020546bffffffffffffffffffffffff16610973565b336000908152600a60205260409020546bffffffffffffffffffffffff80831691161015610973576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906109a09084906bffffffffffffffffffffffff1661450c565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506109f57f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b158015610a7457600080fd5b505af1158015610a88573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b9a6126ff565b610ba2612707565b6000610bac610de2565b905060005b8151811015610d8e576000600a6000848481518110610bd257610bd2614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d7d576000600a6000858581518110610c3157610c31614531565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610cc87f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610cf557610cf5614531565b6020026020010151836040518363ffffffff1660e01b8152600401610d4a92919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d6457600080fd5b505af1158015610d78573d6000803e3d6000fd5b505050505b50610d8781614560565b9050610bb1565b5050565b610d9a61267c565b6000819003610dd5576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105ec82848361439a565b60606006805480602002602001604051908101604052809291908181526020018280548015610e4757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e1c575b5050505050905090565b6060600d8054610e6090614301565b9050600003610e9b576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610ea890614301565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed490614301565b8015610e475780601f10610ef657610100808354040283529160200191610e47565b820191906000526020600020905b815481529060010190602001808311610f0457509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f91576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f416906108369083815260200190565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461109c576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110ad6110a883614598565b6128b3565b90506110bf60608301604084016142e4565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff3261110d60c0870160a08801614685565b61111f610160880161014089016142e4565b61112988806146a2565b61113b6101208b016101008c01614707565b60208b01356111516101008d0160e08e01614722565b8b6040516111679998979695949392919061473f565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16040805160608101825260025480825260035460ff8082166020850152610100909104169282019290925290831461125c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f636f6e666967446967657374206d69736d6174636800000000000000000000006044820152606401610b0d565b61126a8b8b8b8b8b8b612d51565b60007f0000000000000000000000000000000000000000000000000000000000000000156112c7576002826020015183604001516112a891906147e7565b6112b2919061482f565b6112bd9060016147e7565b60ff1690506112dd565b60208201516112d79060016147e7565b60ff1690505b888114611346576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610b0d565b8887146113af576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f7369676e617475726573206f7574206f6620726567697374726174696f6e00006044820152606401610b0d565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113f2576113f2614851565b600281111561140357611403614851565b905250905060028160200151600281111561142057611420614851565b14801561146757506006816000015160ff168154811061144257611442614531565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff1633145b6114cd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610b0d565b50505050506114da613893565b6000808a8a6040516114ed929190614880565b604051908190038120611504918e90602001614890565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b8981101561180e57600060018489846020811061156d5761156d614531565b61157a91901a601b6147e7565b8e8e8681811061158c5761158c614531565b905060200201358d8d878181106115a5576115a5614531565b90506020020135604051600081526020016040526040516115e2949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611604573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff8082168552929650929450840191610100900416600281111561168457611684614851565b600281111561169557611695614851565b90525092506001836020015160028111156116b2576116b2614851565b14611719576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610b0d565b8251600090879060ff16601f811061173357611733614531565b602002015173ffffffffffffffffffffffffffffffffffffffff16146117b5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610b0d565b8086846000015160ff16601f81106117cf576117cf614531565b73ffffffffffffffffffffffffffffffffffffffff90921660209290920201526117fa6001866147e7565b9450508061180790614560565b905061154e565b50505061181f833383858e8e612e08565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b1580156118cc57600080fd5b505afa1580156118e0573d6000803e3d6000fd5b5050505066038d7ea4c68000821115611925576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061192f610841565b9050600061197287878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061023c92505050565b905061198085858385612fd7565b98975050505050505050565b6060600c805461199b90614301565b90506000036119d6576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610ea890614301565b855185518560ff16601f831115611a56576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610b0d565b80600003611ac0576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610b0d565b818314611b4e576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610b0d565b611b598160036148a4565b8311611bc1576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610b0d565b611bc961267c565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611c109088613144565b60055415611dc557600554600090611c2a906001906148bb565b9050600060058281548110611c4157611c41614531565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611c7b57611c7b614531565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611cfb57611cfb6148ce565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611d6457611d646148ce565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611c10915050565b60005b81515181101561222c5760006004600084600001518481518110611dee57611dee614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611e3857611e38614851565b14611e9f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610b0d565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611ed057611ed0614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001617610100836002811115611f7157611f71614851565b021790555060009150611f819050565b6004600084602001518481518110611f9b57611f9b614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611fe557611fe5614851565b1461204c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610b0d565b6040805180820190915260ff82168152602081016002815250600460008460200151848151811061207f5761207f614531565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561212057612120614851565b02179055505082518051600592508390811061213e5761213e614531565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90931692909217909155820151805160069190839081106121ba576121ba614531565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790558061222481614560565b915050611dc8565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff43811682029290921780855592048116929182916014916122e4918491740100000000000000000000000000000000000000009004166148fd565b92506101000a81548163ffffffff021916908363ffffffff1602179055506123434630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a0015161315d565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986123fa988b9891977401000000000000000000000000000000000000000090920463ffffffff1696909591949193919261491a565b60405180910390a15050505050505050505050565b604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c0100000000000000000000000080830482166060850152700100000000000000000000000000000000830468ffffffffffffffffff166080850152790100000000000000000000000000000000000000000000000000830464ffffffffff1660a0808601919091527e0100000000000000000000000000000000000000000000000000000000000090930461ffff1660c08501526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08601527c01000000000000000000000000000000000000000000000000000000009004909116610100840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa15801561259d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125c191906149ca565b5093505092505080426125d491906148bb565b836020015163ffffffff161080156125f657506000836020015163ffffffff16115b1561262457505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b60008213612661576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610b0d565b5092915050565b61267061267c565b61267981613208565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146126fd576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0d565b565b6126fd61267c565b600b546bffffffffffffffffffffffff1660000361272157565b600061272b610de2565b8051909150600081900361276b576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b5460009061278a9083906bffffffffffffffffffffffff16614a1a565b905060005b828110156128555781600a60008684815181106127ae576127ae614531565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff166128169190614a45565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508061284e90614560565b905061278f565b506128608282614a6a565b600b80546000906128809084906bffffffffffffffffffffffff1661450c565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c0100000000000000000000000081048316606083015268ffffffffffffffffff700100000000000000000000000000000000820416608083015264ffffffffff79010000000000000000000000000000000000000000000000000082041660a083015261ffff7e01000000000000000000000000000000000000000000000000000000000000909104811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08501527c0100000000000000000000000000000000000000000000000000000000900490931661010080840191909152850151919291161115612a6e576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854600090700100000000000000000000000000000000900468ffffffffffffffffff1690506000612aab8560e001513a848860800151612fd7565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612b07576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083610100015163ffffffff1642612b209190614a92565b905060003087604001518860a001518960c001516001612b409190614aa5565b8a5180516020918201206101008d015160e08e0151604051612bf498979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b6040516020818303038152906040528051906020012090506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001846bffffffffffffffffffffffff168152602001886040015173ffffffffffffffffffffffffffffffffffffffff1681526020018860a0015167ffffffffffffffff1681526020018860e0015163ffffffff168152602001886080015168ffffffffffffffffff1681526020018568ffffffffffffffffff168152602001866040015163ffffffff1664ffffffffff168152602001866060015163ffffffff1664ffffffffff1681526020018363ffffffff16815250955085604051602001612d039190613f03565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009384526007909252909120555092949350505050565b6000612d5e8260206148a4565b612d698560206148a4565b612d7588610144614a92565b612d7f9190614a92565b612d899190614a92565b612d94906000614a92565b9050368114612dff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610b0d565b50505050505050565b606080808080612e1a86880188614ba1565b84519499509297509095509350915060ff16801580612e3a575084518114155b80612e46575083518114155b80612e52575082518114155b80612e5e575081518114155b15612e95576040517f0be3632800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015612fc8576000612f2d888381518110612eb757612eb7614531565b6020026020010151888481518110612ed157612ed1614531565b6020026020010151888581518110612eeb57612eeb614531565b6020026020010151888681518110612f0557612f05614531565b6020026020010151888781518110612f1f57612f1f614531565b6020026020010151886132fd565b90506000816006811115612f4357612f43614851565b1480612f6057506001816006811115612f5e57612f5e614851565b145b15612fb757878281518110612f7757612f77614531565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b50612fc181614560565b9050612e98565b50505050505050505050505050565b600854600090790100000000000000000000000000000000000000000000000000900464ffffffffff1684101561303257600854790100000000000000000000000000000000000000000000000000900464ffffffffff1693505b6008546000906127109061304c9063ffffffff16876148a4565b6130569190614c73565b6130609086614a92565b60085490915060009087906130999063ffffffff6c010000000000000000000000008204811691680100000000000000009004166148fd565b6130a391906148fd565b63ffffffff16905060006130ed6000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061361192505050565b9050600061310e826130ff85876148a4565b6131099190614a92565b613753565b9050600061312a68ffffffffffffffffff808916908a16614a45565b90506131368183614a45565b9a9950505050505050505050565b600061314e610de2565b511115610d8e57610d8e612707565b6000808a8a8a8a8a8a8a8a8a60405160200161318199989796959493929190614c87565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff821603613287576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b600080848060200190518101906133149190614d53565b905060003a82610120015183610100015161332f9190614e1b565b64ffffffffff1661334091906148a4565b905060008460ff166133886000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061361192505050565b6133929190614c73565b905060006133a36131098385614a92565b905060006133b03a613753565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298e8e868b60e0015168ffffffffffffffffff168961340f9190614a45565b338d6040518763ffffffff1660e01b815260040161343296959493929190614e39565b60408051808303816000875af1158015613450573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134749190614eb5565b9092509050600082600681111561348d5761348d614851565b14806134aa575060018260068111156134a8576134a8614851565b145b156136005760008e8152600760205260408120556134c88185614a45565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0890151600b805468ffffffffffffffffff9092169390929161353491859116614a45565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508d7f90815c2e624694e8010bffad2bcefaf96af282ef1bc2ebc0042d1b89a585e0468487848b60c0015168ffffffffffffffffff168c60e0015168ffffffffffffffffff16878b6135b39190614a45565b6135bd9190614a45565b6135c79190614a45565b604080516bffffffffffffffffffffffff9586168152602081019490945291841683830152909216606082015290519081900360800190a25b509c9b505050505050505050505050565b60004661361d81613787565b1561369957606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561366e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136929190614ee8565b9392505050565b6136a2816137aa565b1561374a5773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e84604051806080016040528060488152602001614f3160489139604051602001613702929190614f01565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161372d9190613bc8565b602060405180830381865afa15801561366e573d6000803e3d6000fd5b50600092915050565b600061378161376061240f565b61377284670de0b6b3a76400006148a4565b61377c9190614c73565b6137f1565b92915050565b600061a4b182148061379b575062066eed82145b8061378157505062066eee1490565b6000600a8214806137bc57506101a482145b806137c9575062aa37dc82145b806137d5575061210582145b806137e2575062014a3382145b8061378157505062014a341490565b60006bffffffffffffffffffffffff82111561388f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b0d565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f8401126138c457600080fd5b50813567ffffffffffffffff8111156138dc57600080fd5b6020830191508360208285010111156138f457600080fd5b9250929050565b6000806020838503121561390e57600080fd5b823567ffffffffffffffff81111561392557600080fd5b613931858286016138b2565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff811182821017156139905761399061393d565b60405290565b604051610160810167ffffffffffffffff811182821017156139905761399061393d565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613a0157613a0161393d565b604052919050565b63ffffffff8116811461267957600080fd5b803561117081613a09565b68ffffffffffffffffff8116811461267957600080fd5b803561117081613a26565b64ffffffffff8116811461267957600080fd5b803561117081613a48565b803561ffff8116811461117057600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461117057600080fd5b60006101208284031215613ab757600080fd5b613abf61396c565b613ac883613a1b565b8152613ad660208401613a1b565b6020820152613ae760408401613a1b565b6040820152613af860608401613a1b565b6060820152613b0960808401613a3d565b6080820152613b1a60a08401613a5b565b60a0820152613b2b60c08401613a66565b60c0820152613b3c60e08401613a78565b60e0820152610100613b4f818501613a1b565b908201529392505050565b60005b83811015613b75578181015183820152602001613b5d565b50506000910152565b60008151808452613b96816020860160208601613b5a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006136926020830184613b7e565b600082601f830112613bec57600080fd5b813567ffffffffffffffff811115613c0657613c0661393d565b613c3760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016139ba565b818152846020838601011115613c4c57600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215613c7b57600080fd5b813567ffffffffffffffff811115613c9257600080fd5b613c9e84828501613bdb565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461267957600080fd5b803561117081613ca6565b6bffffffffffffffffffffffff8116811461267957600080fd5b803561117081613cd3565b60008060408385031215613d0b57600080fd5b8235613d1681613ca6565b91506020830135613d2681613cd3565b809150509250929050565b600081518084526020808501945080840160005b83811015613d7757815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613d45565b509495945050505050565b6020815260006136926020830184613d31565b600060208284031215613da757600080fd5b5035919050565b600060208284031215613dc057600080fd5b813567ffffffffffffffff811115613dd757600080fd5b8201610160818503121561369257600080fd5b805182526020810151613e15602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613e3560408401826bffffffffffffffffffffffff169052565b506060810151613e5d606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613e79608084018267ffffffffffffffff169052565b5060a0810151613e9160a084018263ffffffff169052565b5060c0810151613eae60c084018268ffffffffffffffffff169052565b5060e0810151613ecb60e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b61016081016137818284613dea565b60008083601f840112613f2457600080fd5b50813567ffffffffffffffff811115613f3c57600080fd5b6020830191508360208260051b85010111156138f457600080fd5b60008060008060008060008060e0898b031215613f7357600080fd5b606089018a811115613f8457600080fd5b8998503567ffffffffffffffff80821115613f9e57600080fd5b613faa8c838d016138b2565b909950975060808b0135915080821115613fc357600080fd5b613fcf8c838d01613f12565b909750955060a08b0135915080821115613fe857600080fd5b50613ff58b828c01613f12565b999c989b50969995989497949560c00135949350505050565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151614062608084018268ffffffffffffffffff169052565b5060a083015161407b60a084018264ffffffffff169052565b5060c083015161409160c084018261ffff169052565b5060e08301516140c160e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b506101008381015163ffffffff8116848301525b505092915050565b67ffffffffffffffff8116811461267957600080fd5b8035611170816140dd565b60008060008060006080868803121561411657600080fd5b8535614121816140dd565b9450602086013567ffffffffffffffff81111561413d57600080fd5b614149888289016138b2565b909550935050604086013561415d81613a09565b949793965091946060013592915050565b600067ffffffffffffffff8211156141885761418861393d565b5060051b60200190565b600082601f8301126141a357600080fd5b813560206141b86141b38361416e565b6139ba565b82815260059290921b840181019181810190868411156141d757600080fd5b8286015b848110156141fb5780356141ee81613ca6565b83529183019183016141db565b509695505050505050565b803560ff8116811461117057600080fd5b60008060008060008060c0878903121561423057600080fd5b863567ffffffffffffffff8082111561424857600080fd5b6142548a838b01614192565b9750602089013591508082111561426a57600080fd5b6142768a838b01614192565b965061428460408a01614206565b9550606089013591508082111561429a57600080fd5b6142a68a838b01613bdb565b94506142b460808a016140f3565b935060a08901359150808211156142ca57600080fd5b506142d789828a01613bdb565b9150509295509295509295565b6000602082840312156142f657600080fd5b813561369281613ca6565b600181811c9082168061431557607f821691505b60208210810361434e577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105ec57600081815260208120601f850160051c8101602086101561437b5750805b601f850160051c820191505b81811015610a8857828155600101614387565b67ffffffffffffffff8311156143b2576143b261393d565b6143c6836143c08354614301565b83614354565b6000601f84116001811461441857600085156143e25750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b1783556144ae565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156144675786850135825560209485019460019092019101614447565b50868210156144a2577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b805161117081613a26565b6000602082840312156144d257600080fd5b815161369281613a26565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff828116828216039080821115612661576126616144dd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614591576145916144dd565b5060010190565b600061016082360312156145ab57600080fd5b6145b3613996565b823567ffffffffffffffff8111156145ca57600080fd5b6145d636828601613bdb565b825250602083013560208201526145ef60408401613cc8565b604082015261460060608401613ced565b606082015261461160808401613a3d565b608082015261462260a084016140f3565b60a082015261463360c084016140f3565b60c082015261464460e08401613a1b565b60e0820152610100614657818501613a66565b908201526101206146698482016140f3565b9082015261014061467b848201613cc8565b9082015292915050565b60006020828403121561469757600080fd5b8135613692816140dd565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126146d757600080fd5b83018035915067ffffffffffffffff8211156146f257600080fd5b6020019150368190038213156138f457600080fd5b60006020828403121561471957600080fd5b61369282613a66565b60006020828403121561473457600080fd5b813561369281613a09565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061313660e0830184613dea565b60ff8181168382160190811115613781576137816144dd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061484257614842614800565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b8082028115828204841417613781576137816144dd565b81810381811115613781576137816144dd565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff818116838216019080821115612661576126616144dd565b600061012063ffffffff808d1684528b6020850152808b1660408501525080606084015261494a8184018a613d31565b9050828103608084015261495e8189613d31565b905060ff871660a084015282810360c084015261497b8187613b7e565b905067ffffffffffffffff851660e08401528281036101008401526149a08185613b7e565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461117057600080fd5b600080600080600060a086880312156149e257600080fd5b6149eb866149b0565b9450602086015193506040860151925060608601519150614a0e608087016149b0565b90509295509295909350565b60006bffffffffffffffffffffffff80841680614a3957614a39614800565b92169190910492915050565b6bffffffffffffffffffffffff818116838216019080821115612661576126616144dd565b6bffffffffffffffffffffffff8181168382160280821691908281146140d5576140d56144dd565b80820180821115613781576137816144dd565b67ffffffffffffffff818116838216019080821115612661576126616144dd565b600082601f830112614ad757600080fd5b81356020614ae76141b38361416e565b82815260059290921b84018101918181019086841115614b0657600080fd5b8286015b848110156141fb5780358352918301918301614b0a565b600082601f830112614b3257600080fd5b81356020614b426141b38361416e565b82815260059290921b84018101918181019086841115614b6157600080fd5b8286015b848110156141fb57803567ffffffffffffffff811115614b855760008081fd5b614b938986838b0101613bdb565b845250918301918301614b65565b600080600080600060a08688031215614bb957600080fd5b853567ffffffffffffffff80821115614bd157600080fd5b614bdd89838a01614ac6565b96506020880135915080821115614bf357600080fd5b614bff89838a01614b21565b95506040880135915080821115614c1557600080fd5b614c2189838a01614b21565b94506060880135915080821115614c3757600080fd5b614c4389838a01614b21565b93506080880135915080821115614c5957600080fd5b50614c6688828901614b21565b9150509295509295909350565b600082614c8257614c82614800565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614cce8285018b613d31565b91508382036080850152614ce2828a613d31565b915060ff881660a085015283820360c0850152614cff8288613b7e565b90861660e085015283810361010085015290506149a08185613b7e565b805161117081613ca6565b805161117081613cd3565b8051611170816140dd565b805161117081613a09565b805161117081613a48565b60006101608284031215614d6657600080fd5b614d6e613996565b82518152614d7e60208401614d1c565b6020820152614d8f60408401614d27565b6040820152614da060608401614d1c565b6060820152614db160808401614d32565b6080820152614dc260a08401614d3d565b60a0820152614dd360c084016144b5565b60c0820152614de460e084016144b5565b60e0820152610100614df7818501614d48565b90820152610120614e09848201614d48565b90820152610140613b4f848201614d3d565b64ffffffffff818116838216019080821115612661576126616144dd565b6000610200808352614e4d8184018a613b7e565b90508281036020840152614e618189613b7e565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614eaa905060a0830184613dea565b979650505050505050565b60008060408385031215614ec857600080fd5b825160078110614ed757600080fd5b6020840151909250613d2681613cd3565b600060208284031215614efa57600080fd5b5051919050565b60008351614f13818460208801613b5a565b835190830190614f27818360208801613b5a565b0194935050505056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"router\",\"type\":\"address\"},{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"},{\"internalType\":\"address\",\"name\":\"linkToNativeFeed\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPublicKey\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InconsistentReportData\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InsufficientBalance\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCalldata\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"InvalidConfig\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"int256\",\"name\":\"linkWei\",\"type\":\"int256\"}],\"name\":\"InvalidLinkWeiPrice\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSubscription\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"MustBeSubOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NoTransmittersSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouter\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"OnlyCallableByRouterOwner\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PaymentTooLarge\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"message\",\"type\":\"string\"}],\"name\":\"ReportInvalid\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"RouterMustBeSet\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedPublicKeyChange\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnauthorizedSender\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"UnsupportedRequestDataVersion\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"CommitmentDeleted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"previousConfigBlockNumber\",\"type\":\"uint32\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"configCount\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"signers\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"address[]\",\"name\":\"transmitters\",\"type\":\"address[]\"},{\"indexed\":false,\"internalType\":\"uint8\",\"name\":\"f\",\"type\":\"uint8\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"onchainConfig\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"offchainConfigVersion\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"offchainConfig\",\"type\":\"bytes\"}],\"name\":\"ConfigSet\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"ConfigUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"requestInitiator\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"indexed\":false,\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"callbackGasLimit\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"indexed\":false,\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"name\":\"OracleRequest\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"transmitter\",\"type\":\"address\"}],\"name\":\"OracleResponse\",\"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\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"juelsPerGas\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"l1FeeShareWei\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"callbackCostJuels\",\"type\":\"uint96\"},{\"indexed\":false,\"internalType\":\"uint96\",\"name\":\"totalCostJuels\",\"type\":\"uint96\"}],\"name\":\"RequestBilled\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"name\":\"Transmitted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"acceptOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"}],\"name\":\"deleteCommitment\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"gasPriceWei\",\"type\":\"uint256\"}],\"name\":\"estimateCost\",\"outputs\":[{\"internalType\":\"uint96\",\"name\":\"\",\"type\":\"uint96\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getAdminFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getConfig\",\"outputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"getDONFee\",\"outputs\":[{\"internalType\":\"uint72\",\"name\":\"\",\"type\":\"uint72\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getDONPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getThresholdPublicKey\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getWeiPerUnitLink\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDetails\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"configCount\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestConfigDigestAndEpoch\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"scanLogs\",\"type\":\"bool\"},{\"internalType\":\"bytes32\",\"name\":\"configDigest\",\"type\":\"bytes32\"},{\"internalType\":\"uint32\",\"name\":\"epoch\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"amount\",\"type\":\"uint96\"}],\"name\":\"oracleWithdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracleWithdrawAll\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address[]\",\"name\":\"_signers\",\"type\":\"address[]\"},{\"internalType\":\"address[]\",\"name\":\"_transmitters\",\"type\":\"address[]\"},{\"internalType\":\"uint8\",\"name\":\"_f\",\"type\":\"uint8\"},{\"internalType\":\"bytes\",\"name\":\"_onchainConfig\",\"type\":\"bytes\"},{\"internalType\":\"uint64\",\"name\":\"_offchainConfigVersion\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"_offchainConfig\",\"type\":\"bytes\"}],\"name\":\"setConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"donPublicKey\",\"type\":\"bytes\"}],\"name\":\"setDONPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"thresholdPublicKey\",\"type\":\"bytes\"}],\"name\":\"setThresholdPublicKey\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"bytes32\",\"name\":\"flags\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"requestingContract\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"availableBalance\",\"type\":\"uint96\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"initiatedRequests\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint16\",\"name\":\"dataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint64\",\"name\":\"completedRequests\",\"type\":\"uint64\"},{\"internalType\":\"address\",\"name\":\"subscriptionOwner\",\"type\":\"address\"}],\"internalType\":\"structFunctionsResponse.RequestMeta\",\"name\":\"request\",\"type\":\"tuple\"}],\"name\":\"startRequest\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"requestId\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"coordinator\",\"type\":\"address\"},{\"internalType\":\"uint96\",\"name\":\"estimatedTotalCostJuels\",\"type\":\"uint96\"},{\"internalType\":\"address\",\"name\":\"client\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"subscriptionId\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"callbackGasLimit\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"adminFee\",\"type\":\"uint72\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint40\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint40\"},{\"internalType\":\"uint32\",\"name\":\"timeoutTimestamp\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsResponse.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32[3]\",\"name\":\"reportContext\",\"type\":\"bytes32[3]\"},{\"internalType\":\"bytes\",\"name\":\"report\",\"type\":\"bytes\"},{\"internalType\":\"bytes32[]\",\"name\":\"rs\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32[]\",\"name\":\"ss\",\"type\":\"bytes32[]\"},{\"internalType\":\"bytes32\",\"name\":\"rawVs\",\"type\":\"bytes32\"}],\"name\":\"transmit\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"transmitters\",\"outputs\":[{\"internalType\":\"address[]\",\"name\":\"\",\"type\":\"address[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"typeAndVersion\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"fulfillmentGasPriceOverEstimationBP\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"feedStalenessSeconds\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadBeforeCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint32\",\"name\":\"gasOverheadAfterCallback\",\"type\":\"uint32\"},{\"internalType\":\"uint72\",\"name\":\"donFee\",\"type\":\"uint72\"},{\"internalType\":\"uint40\",\"name\":\"minimumEstimateGasPriceWei\",\"type\":\"uint40\"},{\"internalType\":\"uint16\",\"name\":\"maxSupportedRequestDataVersion\",\"type\":\"uint16\"},{\"internalType\":\"uint224\",\"name\":\"fallbackNativePerUnitLink\",\"type\":\"uint224\"},{\"internalType\":\"uint32\",\"name\":\"requestTimeoutSeconds\",\"type\":\"uint32\"}],\"internalType\":\"structFunctionsBilling.Config\",\"name\":\"config\",\"type\":\"tuple\"}],\"name\":\"updateConfig\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60a06040523480156200001157600080fd5b50604051620057423803806200574283398101604081905262000034916200046d565b8282828233806000816200008f5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000c257620000c28162000139565b5050506001600160a01b038116620000ed57604051632530e88560e11b815260040160405180910390fd5b6001600160a01b03908116608052600b80549183166c01000000000000000000000000026001600160601b039092169190911790556200012d82620001e4565b5050505050506200062c565b336001600160a01b03821603620001935760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000086565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b620001ee62000342565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff16600160f01b026001600160f01b0364ffffffffff909216600160c81b0264ffffffffff60c81b196001600160481b03909416600160801b0293909316600160801b600160f01b031963ffffffff9586166c010000000000000000000000000263ffffffff60601b19978716680100000000000000000297909716600160401b600160801b0319998716640100000000026001600160401b0319909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e0830151610100840151909216600160e01b026001600160e01b0390921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f5184862906200033790839062000576565b60405180910390a150565b6200034c6200034e565b565b6000546001600160a01b031633146200034c5760405162461bcd60e51b815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640162000086565b80516001600160a01b0381168114620003c257600080fd5b919050565b60405161012081016001600160401b0381118282101715620003f957634e487b7160e01b600052604160045260246000fd5b60405290565b805163ffffffff81168114620003c257600080fd5b80516001600160481b0381168114620003c257600080fd5b805164ffffffffff81168114620003c257600080fd5b805161ffff81168114620003c257600080fd5b80516001600160e01b0381168114620003c257600080fd5b60008060008385036101608112156200048557600080fd5b6200049085620003aa565b935061012080601f1983011215620004a757600080fd5b620004b1620003c7565b9150620004c160208701620003ff565b8252620004d160408701620003ff565b6020830152620004e460608701620003ff565b6040830152620004f760808701620003ff565b60608301526200050a60a0870162000414565b60808301526200051d60c087016200042c565b60a08301526200053060e0870162000442565b60c08301526101006200054581880162000455565b60e084015262000557828801620003ff565b908301525091506200056d6101408501620003aa565b90509250925092565b815163ffffffff908116825260208084015182169083015260408084015182169083015260608084015191821690830152610120820190506080830151620005c960808401826001600160481b03169052565b5060a0830151620005e360a084018264ffffffffff169052565b5060c0830151620005fa60c084018261ffff169052565b5060e08301516200061660e08401826001600160e01b03169052565b506101009283015163ffffffff16919092015290565b6080516150d06200067260003960008181610845015281816109d301528181610ca601528181610f3a0152818161104501528181611789015261350201526150d06000f3fe608060405234801561001057600080fd5b506004361061018d5760003560e01c806381ff7048116100e3578063c3f909d41161008c578063e3d0e71211610066578063e3d0e71214610560578063e4ddcea614610573578063f2fde38b1461058957600080fd5b8063c3f909d4146103b0578063d227d24514610528578063d328a91e1461055857600080fd5b8063a631571e116100bd578063a631571e1461035d578063afcb95d71461037d578063b1dc65a41461039d57600080fd5b806381ff7048146102b557806385b214cf146103225780638da5cb5b1461033557600080fd5b806366316d8d116101455780637f15e1661161011f5780637f15e16614610285578063814118341461029857806381f1b938146102ad57600080fd5b806366316d8d1461026257806379ba5097146102755780637d4807871461027d57600080fd5b8063181f5a7711610176578063181f5a77146101ba5780632a905ccc1461020c57806359b5b7ac1461022e57600080fd5b8063083a5466146101925780631112dadc146101a7575b600080fd5b6101a56101a0366004613a46565b61059c565b005b6101a56101b5366004613bef565b6105f1565b6101f66040518060400160405280601c81526020017f46756e6374696f6e7320436f6f7264696e61746f722076312e312e300000000081525081565b6040516102039190613d13565b60405180910390f35b610214610841565b60405168ffffffffffffffffff9091168152602001610203565b61021461023c366004613db4565b50600854700100000000000000000000000000000000900468ffffffffffffffffff1690565b6101a5610270366004613e43565b6108d7565b6101a5610a90565b6101a5610b92565b6101a5610293366004613a46565b610d92565b6102a0610de2565b6040516102039190613ecd565b6101f6610e51565b6102ff60015460025463ffffffff74010000000000000000000000000000000000000000830481169378010000000000000000000000000000000000000000000000009093041691565b6040805163ffffffff948516815293909216602084015290820152606001610203565b6101a5610330366004613ee0565b610f22565b60005460405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610203565b61037061036b366004613ef9565b610fd4565b604051610203919061404e565b604080516001815260006020820181905291810191909152606001610203565b6101a56103ab3660046140a2565b611175565b61051b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915250604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c01000000000000000000000000810483166060830152700100000000000000000000000000000000810468ffffffffffffffffff166080830152790100000000000000000000000000000000000000000000000000810464ffffffffff1660a08301527e01000000000000000000000000000000000000000000000000000000000000900461ffff1660c08201526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08301527c0100000000000000000000000000000000000000000000000000000000900490911661010082015290565b6040516102039190614159565b61053b610536366004614249565b611785565b6040516bffffffffffffffffffffffff9091168152602001610203565b6101f66118e5565b6101a561056e366004614362565b61193c565b61057b6124b8565b604051908152602001610203565b6101a561059736600461442f565b612711565b6105a4612725565b60008190036105df576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d6105ec8284836144e5565b505050565b6105f96127a8565b80516008805460208401516040808601516060870151608088015160a089015160c08a015161ffff167e01000000000000000000000000000000000000000000000000000000000000027dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff64ffffffffff909216790100000000000000000000000000000000000000000000000000027fffff0000000000ffffffffffffffffffffffffffffffffffffffffffffffffff68ffffffffffffffffff90941670010000000000000000000000000000000002939093167fffff0000000000000000000000000000ffffffffffffffffffffffffffffffff63ffffffff9586166c01000000000000000000000000027fffffffffffffffffffffffffffffffff00000000ffffffffffffffffffffffff9787166801000000000000000002979097167fffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffff998716640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909b169c87169c909c1799909917979097169990991793909317959095169390931793909317929092169390931790915560e08301516101008401519092167c0100000000000000000000000000000000000000000000000000000000027bffffffffffffffffffffffffffffffffffffffffffffffffffffffff90921691909117600955517f5f32d06f5e83eda3a68e0e964ef2e6af5cb613e8117aa103c2d6bca5f518486290610836908390614159565b60405180910390a150565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632a905ccc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ae573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d2919061460b565b905090565b6108df6127b0565b806bffffffffffffffffffffffff166000036109195750336000908152600a60205260409020546bffffffffffffffffffffffff16610973565b336000908152600a60205260409020546bffffffffffffffffffffffff80831691161015610973576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000908152600a6020526040812080548392906109a09084906bffffffffffffffffffffffff16614657565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055506109f57f000000000000000000000000000000000000000000000000000000000000000090565b6040517f66316d8d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301526bffffffffffffffffffffffff8416602483015291909116906366316d8d90604401600060405180830381600087803b158015610a7457600080fd5b505af1158015610a88573d6000803e3d6000fd5b505050505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b16576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e65720000000000000000000060448201526064015b60405180910390fd5b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b610b9a6127a8565b610ba26127b0565b6000610bac610de2565b905060005b8151811015610d8e576000600a6000848481518110610bd257610bd261467c565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252810191909152604001600020546bffffffffffffffffffffffff1690508015610d7d576000600a6000858581518110610c3157610c3161467c565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550610cc87f000000000000000000000000000000000000000000000000000000000000000090565b73ffffffffffffffffffffffffffffffffffffffff166366316d8d848481518110610cf557610cf561467c565b6020026020010151836040518363ffffffff1660e01b8152600401610d4a92919073ffffffffffffffffffffffffffffffffffffffff9290921682526bffffffffffffffffffffffff16602082015260400190565b600060405180830381600087803b158015610d6457600080fd5b505af1158015610d78573d6000803e3d6000fd5b505050505b50610d87816146ab565b9050610bb1565b5050565b610d9a612725565b6000819003610dd5576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c6105ec8284836144e5565b60606006805480602002602001604051908101604052809291908181526020018280548015610e4757602002820191906000526020600020905b815473ffffffffffffffffffffffffffffffffffffffff168152600190910190602001808311610e1c575b5050505050905090565b6060600d8054610e609061444c565b9050600003610e9b576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600d8054610ea89061444c565b80601f0160208091040260200160405190810160405280929190818152602001828054610ed49061444c565b8015610e475780601f10610ef657610100808354040283529160200191610e47565b820191906000526020600020905b815481529060010190602001808311610f0457509395945050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610f91576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008181526007602052604080822091909155517f8a4b97add3359bd6bcf5e82874363670eb5ad0f7615abddbd0ed0a3a98f0f416906108369083815260200190565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091523373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461109c576040517fc41a5b0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110ad6110a8836146e3565b61295c565b90506110bf606083016040840161442f565b815173ffffffffffffffffffffffffffffffffffffffff91909116907fbf50768ccf13bd0110ca6d53a9c4f1f3271abdd4c24a56878863ed25b20598ff3261110d60c0870160a088016147d0565b61111f6101608801610140890161442f565b61112988806147ed565b61113b6101208b016101008c01614852565b60208b01356111516101008d0160e08e0161486d565b8b6040516111679998979695949392919061488a565b60405180910390a35b919050565b60005a604080518b3580825262ffffff6020808f0135600881901c929092169084015293945092917fb04e63db38c49950639fa09d29872f21f5d49d614f3a969d8adf3d4b52e41a62910160405180910390a16111d68a8a8a8a8a8a612dfa565b6003546000906002906111f49060ff80821691610100900416614932565b6111fe919061497a565b611209906001614932565b60ff169050878114611277576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f77726f6e67206e756d626572206f66207369676e6174757265730000000000006044820152606401610b0d565b878614611306576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f7265706f727420727320616e64207373206d757374206265206f66206571756160448201527f6c206c656e6774680000000000000000000000000000000000000000000000006064820152608401610b0d565b3360009081526004602090815260408083208151808301909252805460ff808216845292939192918401916101009091041660028111156113495761134961499c565b600281111561135a5761135a61499c565b90525090506002816020015160028111156113775761137761499c565b141580156113c057506006816000015160ff168154811061139a5761139a61467c565b60009182526020909120015473ffffffffffffffffffffffffffffffffffffffff163314155b15611427576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f756e617574686f72697a6564207472616e736d697474657200000000000000006044820152606401610b0d565b505050506114336139de565b6000808a8a6040516114469291906149cb565b60405190819003812061145d918e906020016149db565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120838301909252600080845290830152915060005b898110156117675760006001848984602081106114c6576114c661467c565b6114d391901a601b614932565b8e8e868181106114e5576114e561467c565b905060200201358d8d878181106114fe576114fe61467c565b905060200201356040516000815260200160405260405161153b949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa15801561155d573d6000803e3d6000fd5b5050604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081015173ffffffffffffffffffffffffffffffffffffffff811660009081526004602090815290849020838501909452835460ff808216855292965092945084019161010090041660028111156115dd576115dd61499c565b60028111156115ee576115ee61499c565b905250925060018360200151600281111561160b5761160b61499c565b14611672576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f61646472657373206e6f7420617574686f72697a656420746f207369676e00006044820152606401610b0d565b8251600090879060ff16601f811061168c5761168c61467c565b602002015173ffffffffffffffffffffffffffffffffffffffff161461170e576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f6e6f6e2d756e69717565207369676e61747572650000000000000000000000006044820152606401610b0d565b8086846000015160ff16601f81106117285761172861467c565b73ffffffffffffffffffffffffffffffffffffffff9092166020929092020152611753600186614932565b94505080611760906146ab565b90506114a7565b505050611778833383858e8e612eb1565b5050505050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006040517f10fc49c100000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8816600482015263ffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff91909116906310fc49c19060440160006040518083038186803b15801561182557600080fd5b505afa158015611839573d6000803e3d6000fd5b5050505066038d7ea4c6800082111561187e576040517f8129bbcd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611888610841565b905060006118cb87878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061023c92505050565b90506118d985858385613122565b98975050505050505050565b6060600c80546118f49061444c565b905060000361192f576040517f4f42be3d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c8054610ea89061444c565b855185518560ff16601f8311156119af576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f746f6f206d616e79207369676e657273000000000000000000000000000000006044820152606401610b0d565b80600003611a19576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f66206d75737420626520706f73697469766500000000000000000000000000006044820152606401610b0d565b818314611aa7576040517f89a61989000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f6f7261636c6520616464726573736573206f7574206f6620726567697374726160448201527f74696f6e000000000000000000000000000000000000000000000000000000006064820152608401610b0d565b611ab28160036149ef565b8311611b1a576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f6661756c74792d6f7261636c65206620746f6f206869676800000000000000006044820152606401610b0d565b611b22612725565b6040805160c0810182528a8152602081018a905260ff89169181018290526060810188905267ffffffffffffffff8716608082015260a0810186905290611b69908861328f565b60055415611d1e57600554600090611b8390600190614a06565b9050600060058281548110611b9a57611b9a61467c565b60009182526020822001546006805473ffffffffffffffffffffffffffffffffffffffff90921693509084908110611bd457611bd461467c565b600091825260208083209091015473ffffffffffffffffffffffffffffffffffffffff85811684526004909252604080842080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000090811690915592909116808452922080549091169055600580549192509080611c5457611c54614a19565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690550190556006805480611cbd57611cbd614a19565b60008281526020902081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90810180547fffffffffffffffffffffffff000000000000000000000000000000000000000016905501905550611b69915050565b60005b8151518110156122d557815180516000919083908110611d4357611d4361467c565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611dc8576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f7369676e6572206d757374206e6f7420626520656d70747900000000000000006044820152606401610b0d565b600073ffffffffffffffffffffffffffffffffffffffff1682602001518281518110611df657611df661467c565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603611e7b576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f7472616e736d6974746572206d757374206e6f7420626520656d7074790000006044820152606401610b0d565b60006004600084600001518481518110611e9757611e9761467c565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff166002811115611ee157611ee161499c565b14611f48576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f7265706561746564207369676e657220616464726573730000000000000000006044820152606401610b0d565b6040805180820190915260ff82168152600160208201528251805160049160009185908110611f7957611f7961467c565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000161761010083600281111561201a5761201a61499c565b02179055506000915061202a9050565b60046000846020015184815181106120445761204461467c565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff16825281019190915260400160002054610100900460ff16600281111561208e5761208e61499c565b146120f5576040517f89a6198900000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f7265706561746564207472616e736d69747465722061646472657373000000006044820152606401610b0d565b6040805180820190915260ff8216815260208101600281525060046000846020015184815181106121285761212861467c565b60209081029190910181015173ffffffffffffffffffffffffffffffffffffffff168252818101929092526040016000208251815460ff9091167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082168117835592840151919283917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000016176101008360028111156121c9576121c961499c565b0217905550508251805160059250839081106121e7576121e761467c565b602090810291909101810151825460018101845560009384529282902090920180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff90931692909217909155820151805160069190839081106122635761226361467c565b60209081029190910181015182546001810184556000938452919092200180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055806122cd816146ab565b915050611d21565b506040810151600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff909216919091179055600180547fffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff8116780100000000000000000000000000000000000000000000000063ffffffff438116820292909217808555920481169291829160149161238d91849174010000000000000000000000000000000000000000900416614a48565b92506101000a81548163ffffffff021916908363ffffffff1602179055506123ec4630600160149054906101000a900463ffffffff1663ffffffff16856000015186602001518760400151886060015189608001518a60a001516132a8565b600281905582518051600380547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010060ff9093169290920291909117905560015460208501516040808701516060880151608089015160a08a015193517f1591690b8638f5fb2dbec82ac741805ac5da8b45dc5263f4875b0496fdce4e05986124a3988b9891977401000000000000000000000000000000000000000090920463ffffffff16969095919491939192614a65565b60405180910390a15050505050505050505050565b604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116838501526c0100000000000000000000000080830482166060850152700100000000000000000000000000000000830468ffffffffffffffffff166080850152790100000000000000000000000000000000000000000000000000830464ffffffffff1660a0808601919091527e0100000000000000000000000000000000000000000000000000000000000090930461ffff1660c08501526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08601527c01000000000000000000000000000000000000000000000000000000009004909116610100840152600b5484517ffeaf968c00000000000000000000000000000000000000000000000000000000815294516000958694859490930473ffffffffffffffffffffffffffffffffffffffff169263feaf968c926004808401938290030181865afa158015612646573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061266a9190614b15565b50935050925050804261267d9190614a06565b836020015163ffffffff1610801561269f57506000836020015163ffffffff16115b156126cd57505060e001517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16919050565b6000821361270a576040517f43d4cf6600000000000000000000000000000000000000000000000000000000815260048101839052602401610b0d565b5092915050565b612719612725565b61272281613353565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146127a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e6572000000000000000000006044820152606401610b0d565b565b6127a6612725565b600b546bffffffffffffffffffffffff166000036127ca57565b60006127d4610de2565b80519091506000819003612814576040517f30274b3a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600b546000906128339083906bffffffffffffffffffffffff16614b65565b905060005b828110156128fe5781600a60008684815181106128575761285761467c565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282829054906101000a90046bffffffffffffffffffffffff166128bf9190614b90565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550806128f7906146ab565b9050612838565b506129098282614bb5565b600b80546000906129299084906bffffffffffffffffffffffff16614657565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff160217905550505050565b6040805161016081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810191909152604080516101208101825260085463ffffffff80821683526401000000008204811660208401526801000000000000000082048116938301939093526c0100000000000000000000000081048316606083015268ffffffffffffffffff700100000000000000000000000000000000820416608083015264ffffffffff79010000000000000000000000000000000000000000000000000082041660a083015261ffff7e01000000000000000000000000000000000000000000000000000000000000909104811660c083018190526009547bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811660e08501527c0100000000000000000000000000000000000000000000000000000000900490931661010080840191909152850151919291161115612b17576040517fdada758700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600854600090700100000000000000000000000000000000900468ffffffffffffffffff1690506000612b548560e001513a848860800151613122565b9050806bffffffffffffffffffffffff1685606001516bffffffffffffffffffffffff161015612bb0576040517ff4d678b800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600083610100015163ffffffff1642612bc99190614bdd565b905060003087604001518860a001518960c001516001612be99190614bf0565b8a5180516020918201206101008d015160e08e0151604051612c9d98979695948c918c9132910173ffffffffffffffffffffffffffffffffffffffff9a8b168152988a1660208a015267ffffffffffffffff97881660408a0152959096166060880152608087019390935261ffff9190911660a086015263ffffffff90811660c08601526bffffffffffffffffffffffff9190911660e0850152919091166101008301529091166101208201526101400190565b6040516020818303038152906040528051906020012090506040518061016001604052808281526020013073ffffffffffffffffffffffffffffffffffffffff168152602001846bffffffffffffffffffffffff168152602001886040015173ffffffffffffffffffffffffffffffffffffffff1681526020018860a0015167ffffffffffffffff1681526020018860e0015163ffffffff168152602001886080015168ffffffffffffffffff1681526020018568ffffffffffffffffff168152602001866040015163ffffffff1664ffffffffff168152602001866060015163ffffffff1664ffffffffff1681526020018363ffffffff16815250955085604051602001612dac919061404e565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152815160209283012060009384526007909252909120555092949350505050565b6000612e078260206149ef565b612e128560206149ef565b612e1e88610144614bdd565b612e289190614bdd565b612e329190614bdd565b612e3d906000614bdd565b9050368114612ea8576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f63616c6c64617461206c656e677468206d69736d6174636800000000000000006044820152606401610b0d565b50505050505050565b606080808080612ec386880188614cec565b84519499509297509095509350915060ff16801580612ee3575084518114155b80612eef575083518114155b80612efb575082518114155b80612f07575081518114155b15612fe0576040517f660bd4ba00000000000000000000000000000000000000000000000000000000815260206004820152607060248201527f416c6c206669656c6473206f6e20746865207265706f7274206d75737420626560448201527f206f6620657175616c206c656e6774683a20726571756573744964732c20726560648201527f73756c74732c206572726f72732c206f6e636861696e4d657461646174612c2060848201527f6f6666636861696e4d657461646174610000000000000000000000000000000060a482015260c401610b0d565b60005b818110156131135760006130788883815181106130025761300261467c565b602002602001015188848151811061301c5761301c61467c565b60200260200101518885815181106130365761303661467c565b60200260200101518886815181106130505761305061467c565b602002602001015188878151811061306a5761306a61467c565b602002602001015188613448565b9050600081600681111561308e5761308e61499c565b14806130ab575060018160068111156130a9576130a961499c565b145b15613102578782815181106130c2576130c261467c565b60209081029190910181015160405133815290917fc708e0440951fd63499c0f7a73819b469ee5dd3ecc356c0ab4eb7f18389009d9910160405180910390a25b5061310c816146ab565b9050612fe3565b50505050505050505050505050565b600854600090790100000000000000000000000000000000000000000000000000900464ffffffffff1684101561317d57600854790100000000000000000000000000000000000000000000000000900464ffffffffff1693505b600854600090612710906131979063ffffffff16876149ef565b6131a19190614dbe565b6131ab9086614bdd565b60085490915060009087906131e49063ffffffff6c01000000000000000000000000820481169168010000000000000000900416614a48565b6131ee9190614a48565b63ffffffff16905060006132386000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061375c92505050565b905060006132598261324a85876149ef565b6132549190614bdd565b61389e565b9050600061327568ffffffffffffffffff808916908a16614b90565b90506132818183614b90565b9a9950505050505050505050565b6000613299610de2565b511115610d8e57610d8e6127b0565b6000808a8a8a8a8a8a8a8a8a6040516020016132cc99989796959493929190614dd2565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101207dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167e01000000000000000000000000000000000000000000000000000000000000179150509998505050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff8216036133d2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c660000000000000000006044820152606401610b0d565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b6000808480602001905181019061345f9190614e9e565b905060003a82610120015183610100015161347a9190614f66565b64ffffffffff1661348b91906149ef565b905060008460ff166134d36000368080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061375c92505050565b6134dd9190614dbe565b905060006134ee6132548385614bdd565b905060006134fb3a61389e565b90506000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663330605298e8e868b60e0015168ffffffffffffffffff168961355a9190614b90565b338d6040518763ffffffff1660e01b815260040161357d96959493929190614f84565b60408051808303816000875af115801561359b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135bf9190615000565b909250905060008260068111156135d8576135d861499c565b14806135f5575060018260068111156135f3576135f361499c565b145b1561374b5760008e8152600760205260408120556136138185614b90565b336000908152600a6020526040812080547fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166bffffffffffffffffffffffff93841617905560e0890151600b805468ffffffffffffffffff9092169390929161367f91859116614b90565b92506101000a8154816bffffffffffffffffffffffff02191690836bffffffffffffffffffffffff1602179055508d7f90815c2e624694e8010bffad2bcefaf96af282ef1bc2ebc0042d1b89a585e0468487848b60c0015168ffffffffffffffffff168c60e0015168ffffffffffffffffff16878b6136fe9190614b90565b6137089190614b90565b6137129190614b90565b604080516bffffffffffffffffffffffff9586168152602081019490945291841683830152909216606082015290519081900360800190a25b509c9b505050505050505050505050565b600046613768816138d2565b156137e457606c73ffffffffffffffffffffffffffffffffffffffff1663c6f7de0e6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156137b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137dd9190615033565b9392505050565b6137ed816138f5565b156138955773420000000000000000000000000000000000000f73ffffffffffffffffffffffffffffffffffffffff166349948e0e8460405180608001604052806048815260200161507c6048913960405160200161384d92919061504c565b6040516020818303038152906040526040518263ffffffff1660e01b81526004016138789190613d13565b602060405180830381865afa1580156137b9573d6000803e3d6000fd5b50600092915050565b60006138cc6138ab6124b8565b6138bd84670de0b6b3a76400006149ef565b6138c79190614dbe565b61393c565b92915050565b600061a4b18214806138e6575062066eed82145b806138cc57505062066eee1490565b6000600a82148061390757506101a482145b80613914575062aa37dc82145b80613920575061210582145b8061392d575062014a3382145b806138cc57505062014a341490565b60006bffffffffffffffffffffffff8211156139da576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203960448201527f36206269747300000000000000000000000000000000000000000000000000006064820152608401610b0d565b5090565b604051806103e00160405280601f906020820280368337509192915050565b60008083601f840112613a0f57600080fd5b50813567ffffffffffffffff811115613a2757600080fd5b602083019150836020828501011115613a3f57600080fd5b9250929050565b60008060208385031215613a5957600080fd5b823567ffffffffffffffff811115613a7057600080fd5b613a7c858286016139fd565b90969095509350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610120810167ffffffffffffffff81118282101715613adb57613adb613a88565b60405290565b604051610160810167ffffffffffffffff81118282101715613adb57613adb613a88565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715613b4c57613b4c613a88565b604052919050565b63ffffffff8116811461272257600080fd5b803561117081613b54565b68ffffffffffffffffff8116811461272257600080fd5b803561117081613b71565b64ffffffffff8116811461272257600080fd5b803561117081613b93565b803561ffff8116811461117057600080fd5b80357bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8116811461117057600080fd5b60006101208284031215613c0257600080fd5b613c0a613ab7565b613c1383613b66565b8152613c2160208401613b66565b6020820152613c3260408401613b66565b6040820152613c4360608401613b66565b6060820152613c5460808401613b88565b6080820152613c6560a08401613ba6565b60a0820152613c7660c08401613bb1565b60c0820152613c8760e08401613bc3565b60e0820152610100613c9a818501613b66565b908201529392505050565b60005b83811015613cc0578181015183820152602001613ca8565b50506000910152565b60008151808452613ce1816020860160208601613ca5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006137dd6020830184613cc9565b600082601f830112613d3757600080fd5b813567ffffffffffffffff811115613d5157613d51613a88565b613d8260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613b05565b818152846020838601011115613d9757600080fd5b816020850160208301376000918101602001919091529392505050565b600060208284031215613dc657600080fd5b813567ffffffffffffffff811115613ddd57600080fd5b613de984828501613d26565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461272257600080fd5b803561117081613df1565b6bffffffffffffffffffffffff8116811461272257600080fd5b803561117081613e1e565b60008060408385031215613e5657600080fd5b8235613e6181613df1565b91506020830135613e7181613e1e565b809150509250929050565b600081518084526020808501945080840160005b83811015613ec257815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101613e90565b509495945050505050565b6020815260006137dd6020830184613e7c565b600060208284031215613ef257600080fd5b5035919050565b600060208284031215613f0b57600080fd5b813567ffffffffffffffff811115613f2257600080fd5b820161016081850312156137dd57600080fd5b805182526020810151613f60602084018273ffffffffffffffffffffffffffffffffffffffff169052565b506040810151613f8060408401826bffffffffffffffffffffffff169052565b506060810151613fa8606084018273ffffffffffffffffffffffffffffffffffffffff169052565b506080810151613fc4608084018267ffffffffffffffff169052565b5060a0810151613fdc60a084018263ffffffff169052565b5060c0810151613ff960c084018268ffffffffffffffffff169052565b5060e081015161401660e084018268ffffffffffffffffff169052565b506101008181015164ffffffffff9081169184019190915261012080830151909116908301526101409081015163ffffffff16910152565b61016081016138cc8284613f35565b60008083601f84011261406f57600080fd5b50813567ffffffffffffffff81111561408757600080fd5b6020830191508360208260051b8501011115613a3f57600080fd5b60008060008060008060008060e0898b0312156140be57600080fd5b606089018a8111156140cf57600080fd5b8998503567ffffffffffffffff808211156140e957600080fd5b6140f58c838d016139fd565b909950975060808b013591508082111561410e57600080fd5b61411a8c838d0161405d565b909750955060a08b013591508082111561413357600080fd5b506141408b828c0161405d565b999c989b50969995989497949560c00135949350505050565b815163ffffffff9081168252602080840151821690830152604080840151821690830152606080840151918216908301526101208201905060808301516141ad608084018268ffffffffffffffffff169052565b5060a08301516141c660a084018264ffffffffff169052565b5060c08301516141dc60c084018261ffff169052565b5060e083015161420c60e08401827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff169052565b506101008381015163ffffffff8116848301525b505092915050565b67ffffffffffffffff8116811461272257600080fd5b803561117081614228565b60008060008060006080868803121561426157600080fd5b853561426c81614228565b9450602086013567ffffffffffffffff81111561428857600080fd5b614294888289016139fd565b90955093505060408601356142a881613b54565b949793965091946060013592915050565b600067ffffffffffffffff8211156142d3576142d3613a88565b5060051b60200190565b600082601f8301126142ee57600080fd5b813560206143036142fe836142b9565b613b05565b82815260059290921b8401810191818101908684111561432257600080fd5b8286015b8481101561434657803561433981613df1565b8352918301918301614326565b509695505050505050565b803560ff8116811461117057600080fd5b60008060008060008060c0878903121561437b57600080fd5b863567ffffffffffffffff8082111561439357600080fd5b61439f8a838b016142dd565b975060208901359150808211156143b557600080fd5b6143c18a838b016142dd565b96506143cf60408a01614351565b955060608901359150808211156143e557600080fd5b6143f18a838b01613d26565b94506143ff60808a0161423e565b935060a089013591508082111561441557600080fd5b5061442289828a01613d26565b9150509295509295509295565b60006020828403121561444157600080fd5b81356137dd81613df1565b600181811c9082168061446057607f821691505b602082108103614499577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f8211156105ec57600081815260208120601f850160051c810160208610156144c65750805b601f850160051c820191505b81811015610a88578281556001016144d2565b67ffffffffffffffff8311156144fd576144fd613a88565b6145118361450b835461444c565b8361449f565b6000601f841160018114614563576000851561452d5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b1783556145f9565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b828110156145b25786850135825560209485019460019092019101614592565b50868210156145ed577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b805161117081613b71565b60006020828403121561461d57600080fd5b81516137dd81613b71565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6bffffffffffffffffffffffff82811682821603908082111561270a5761270a614628565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036146dc576146dc614628565b5060010190565b600061016082360312156146f657600080fd5b6146fe613ae1565b823567ffffffffffffffff81111561471557600080fd5b61472136828601613d26565b8252506020830135602082015261473a60408401613e13565b604082015261474b60608401613e38565b606082015261475c60808401613b88565b608082015261476d60a0840161423e565b60a082015261477e60c0840161423e565b60c082015261478f60e08401613b66565b60e08201526101006147a2818501613bb1565b908201526101206147b484820161423e565b908201526101406147c6848201613e13565b9082015292915050565b6000602082840312156147e257600080fd5b81356137dd81614228565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261482257600080fd5b83018035915067ffffffffffffffff82111561483d57600080fd5b602001915036819003821315613a3f57600080fd5b60006020828403121561486457600080fd5b6137dd82613bb1565b60006020828403121561487f57600080fd5b81356137dd81613b54565b73ffffffffffffffffffffffffffffffffffffffff8a8116825267ffffffffffffffff8a166020830152881660408201526102406060820181905281018690526000610260878982850137600083890182015261ffff8716608084015260a0830186905263ffffffff851660c0840152601f88017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016830101905061328160e0830184613f35565b60ff81811683821601908111156138cc576138cc614628565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff83168061498d5761498d61494b565b8060ff84160491505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b8183823760009101908152919050565b828152606082602083013760800192915050565b80820281158282048414176138cc576138cc614628565b818103818111156138cc576138cc614628565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b63ffffffff81811683821601908082111561270a5761270a614628565b600061012063ffffffff808d1684528b6020850152808b16604085015250806060840152614a958184018a613e7c565b90508281036080840152614aa98189613e7c565b905060ff871660a084015282810360c0840152614ac68187613cc9565b905067ffffffffffffffff851660e0840152828103610100840152614aeb8185613cc9565b9c9b505050505050505050505050565b805169ffffffffffffffffffff8116811461117057600080fd5b600080600080600060a08688031215614b2d57600080fd5b614b3686614afb565b9450602086015193506040860151925060608601519150614b5960808701614afb565b90509295509295909350565b60006bffffffffffffffffffffffff80841680614b8457614b8461494b565b92169190910492915050565b6bffffffffffffffffffffffff81811683821601908082111561270a5761270a614628565b6bffffffffffffffffffffffff81811683821602808216919082811461422057614220614628565b808201808211156138cc576138cc614628565b67ffffffffffffffff81811683821601908082111561270a5761270a614628565b600082601f830112614c2257600080fd5b81356020614c326142fe836142b9565b82815260059290921b84018101918181019086841115614c5157600080fd5b8286015b848110156143465780358352918301918301614c55565b600082601f830112614c7d57600080fd5b81356020614c8d6142fe836142b9565b82815260059290921b84018101918181019086841115614cac57600080fd5b8286015b8481101561434657803567ffffffffffffffff811115614cd05760008081fd5b614cde8986838b0101613d26565b845250918301918301614cb0565b600080600080600060a08688031215614d0457600080fd5b853567ffffffffffffffff80821115614d1c57600080fd5b614d2889838a01614c11565b96506020880135915080821115614d3e57600080fd5b614d4a89838a01614c6c565b95506040880135915080821115614d6057600080fd5b614d6c89838a01614c6c565b94506060880135915080821115614d8257600080fd5b614d8e89838a01614c6c565b93506080880135915080821115614da457600080fd5b50614db188828901614c6c565b9150509295509295909350565b600082614dcd57614dcd61494b565b500490565b60006101208b835273ffffffffffffffffffffffffffffffffffffffff8b16602084015267ffffffffffffffff808b166040850152816060850152614e198285018b613e7c565b91508382036080850152614e2d828a613e7c565b915060ff881660a085015283820360c0850152614e4a8288613cc9565b90861660e08501528381036101008501529050614aeb8185613cc9565b805161117081613df1565b805161117081613e1e565b805161117081614228565b805161117081613b54565b805161117081613b93565b60006101608284031215614eb157600080fd5b614eb9613ae1565b82518152614ec960208401614e67565b6020820152614eda60408401614e72565b6040820152614eeb60608401614e67565b6060820152614efc60808401614e7d565b6080820152614f0d60a08401614e88565b60a0820152614f1e60c08401614600565b60c0820152614f2f60e08401614600565b60e0820152610100614f42818501614e93565b90820152610120614f54848201614e93565b90820152610140613c9a848201614e88565b64ffffffffff81811683821601908082111561270a5761270a614628565b6000610200808352614f988184018a613cc9565b90508281036020840152614fac8189613cc9565b6bffffffffffffffffffffffff88811660408601528716606085015273ffffffffffffffffffffffffffffffffffffffff861660808501529150614ff5905060a0830184613f35565b979650505050505050565b6000806040838503121561501357600080fd5b82516007811061502257600080fd5b6020840151909250613e7181613e1e565b60006020828403121561504557600080fd5b5051919050565b6000835161505e818460208801613ca5565b835190830190615072818360208801613ca5565b0194935050505056fe307866666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666a164736f6c6343000813000a", } var FunctionsCoordinatorABI = FunctionsCoordinatorMetaData.ABI diff --git a/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt index 534e5543e86..93c4e64a3af 100644 --- a/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/functions/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -4,7 +4,7 @@ functions_allow_list: ../../../contracts/solc/v0.8.19/functions/v1_X/TermsOfServ functions_billing_registry_events_mock: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistryEventsMock.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsBillingRegistryEventsMock.bin 50deeb883bd9c3729702be335c0388f9d8553bab4be5e26ecacac496a89e2b77 functions_client: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClient.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClient.bin 2368f537a04489c720a46733f8596c4fc88a31062ecfa966d05f25dd98608aca functions_client_example: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClientExample.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsClientExample.bin abf32e69f268f40e8530eb8d8e96bf310b798a4c0049a58022d9d2fb527b601b -functions_coordinator: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.bin 38e168fa57c9626140e1e4d05f4124b4b69bd775e6e0f4481e017ad86c4d95a0 +functions_coordinator: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsCoordinator.bin 4e05ca5e624b7a1e604b81b84bc088818b376d533f556ba1c2ee586b7eb38b68 functions_load_test_client: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsLoadTestClient.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsLoadTestClient.bin c8dbbd5ebb34435800d6674700068837c3a252db60046a14b0e61e829db517de functions_oracle_events_mock: ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracleEventsMock.abi ../../../contracts/solc/v0.8.6/functions/v0_0_0/FunctionsOracleEventsMock.bin 3ca70f966f8fe751987f0ccb50bebb6aa5be77e4a9f835d1ae99e0e9bfb7d52c functions_router: ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.abi ../../../contracts/solc/v0.8.19/functions/v1_X/FunctionsRouter.bin 9dedd3a36043605fd9bedf821e7ec5b4281a5c7ae2e4a1955f37aff8ba13519f